"Ленивый ИО" в Хаскеле? - PullRequest
       41

"Ленивый ИО" в Хаскеле?

8 голосов
/ 18 февраля 2010

Я пытаюсь провести небольшой эксперимент на haskell, задаваясь вопросом, можно ли использовать лень для обработки ввода-вывода.Я хотел бы написать функцию, которая принимает строку (список символов) и создает строку, лениво.Тогда я бы хотел лениво кормить его символами ввода-вывода, чтобы каждый символ обрабатывался, как только он был доступен, и вывод получался по мере появления необходимых символов.Тем не менее, я не совсем уверен, смогу ли я / как создать ленивый список символов из ввода внутри монады ввода-вывода.

Ответы [ 3 ]

14 голосов
/ 18 февраля 2010

Обычный строковый ввод-вывод в Хаскеле ленив. Так что ваш пример должен работать из коробки.

Вот пример использования функции «взаимодействовать», которая применяет функцию к ленивому потоку символов:

interact :: (String -> String) -> IO ()

Давайте отфильтруем букву 'e' из входного потока, лениво (то есть запустим в постоянном пространстве):

main = interact $ filter (/= 'e')

Вы также можете использовать getContents и putStr, если хотите. Они все ленивые.

Запуск его для фильтрации буквы 'e' из словаря:

$ ghc -O2 --make A.hs
$ ./A +RTS -s < /usr/share/dict/words
...
               2 MB total memory in use (0 MB lost due to fragmentation)
...

так что мы видим, что он занимал постоянную площадь 2М.

7 голосов
/ 18 февраля 2010

Самый простой метод выполнения ленивых операций ввода-вывода включает такие функции, как interact, readFile, hGetContents и такие, как dons ;в книге Real World Haskell есть более подробное их обсуждение, которое может оказаться полезным.Если мне не изменяет память, все такие функции в конечном итоге реализуются с использованием unsafeInterleaveIO, о котором упоминается ephemient , поэтому вы также можете создавать свои собственные функции таким образом, если хотите.

С другой стороны, было бы разумно отметить, что unsafeInterleaveIO - это именно то, что написано на банке: небезопасный IO .Используя его - или функции на его основе - нарушает чистоту и ссылочную прозрачность .Это позволяет, по-видимому, чистым функциям (то есть, которые не возвращают действие IO) воздействовать на внешний мир при оценке, давать разные результаты из одних и тех же аргументов и всех других неприятных вещей.На практике наиболее разумные способы использования unsafeInterleaveIO не вызовут проблем, а простые ошибки обычно приводят к очевидным и легко диагностируемым ошибкам, но вы потеряли некоторые хорошие гарантии.

Существуют альтернативыкурс;в Hackage можно найти разные библиотеки, которые предоставляют ограниченные, безопасные, ленивые IO или концептуально разные подходы .Однако, учитывая, что проблемы возникают на практике лишь изредка, я думаю, что большинство людей склонны придерживаться встроенных, технически небезопасных функций.

3 голосов
/ 18 февраля 2010
unsafeInterleaveIO :: IO a -> IO a

unsafeInterleaveIO allos IO вычисление, которое будет отложено. Когда передано значение типа IO a, IO будет выполняться только тогда, когда требуется значение a. Это используется для реализации отложенного чтения файлов, см. System.IO.hGetContents.

Например, main = getContents >>= return . map Data.Char.toUpper >>= putStr ленив; когда вы передаете символы на стандартный ввод, вы получаете символы на стандартный вывод.

(Это то же самое, что написать main = interact $ map Data.Char.toUpper, как в ответе дона.)

...