Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
MakeevGA-Haskell-a4-shortcode_2014_05_31.doc
Скачиваний:
15
Добавлен:
19.01.2023
Размер:
1.79 Mб
Скачать

Ввод-вывод

Любая программа будет производить действия ввода-вывода (в самом широком смысле – от вывода чего-нибудь на экран до чтения и записи в порты устройств), если мы вообще хотим получить от нее какой-нибудь полезный выхлоп, кроме загрузки центрального процессора и обогревания комнаты.

Однако даже простая печать на экран в Haskell сопряжена с определенного рода идейными проблемами. Мы ведь говорили о том, что все функции в Haskell не могут иметь побочные эффекты, а что такое ввод-вывод, как не побочные эффекты?

Итак, с одной стороны, функции ничего не могут печатать на экран и читать с клавиатуры, – а с другой стороны, они должны это делать, иначе как программой пользоваться? Для разрешения этой проблемы был использован довольно серьезный механизм – монады. Это такая абстрактная концепция, которая очень много чего может моделировать, и вот выяснилось, что ввод-вывод тоже отлично в монады укладывается.

Нет, чудес не будет, конечно – функциям придется разрешить производить побочные эффекты. Однако система ввода-вывода в Haskell позволяет явно разделить те части программы, где происходит ввод-вывод, где всякие разные плохие побочные эффекты – а где все тот же чистый строгий декларативный код без побочных эффектов.

С первого взгляда (а честно говоря, и со второго, и с третьего тоже), монады – это ужас, летящий на крыльях ночи. Монадами пугают взрослые программисты своих маленьких программистиков. Однако хорошая новость для вас заключается в том, что, как гласит популярная аналогия, понимание монад требуется для работы с вводом-выводом не больше, чем понимание теории групп для использования простой арифметики. И это действительно так. Мы начнем с того, что напишем простейшую программу, производящую ввод-вывод, и вы убедитесь, что это очень просто. А потом попробуем заглянуть немножко за занавес, чтобы увидеть всю (ну, как минимум, часть) кухни, которая там творится.

В монадах (как и в любой другой абстрактной концепции, впрочем) разобраться можно двумя путями. Можно просто принять абстрактные определения, пропустить их через себя, не пытаясь вдумываться в их жизненный смысл – и потом уже пытаться смотреть частные случаи, проявления этих абстракций. А можно идти с другой стороны – сначала разобраться в простом частном применении, потом в другом применении, потом в третьем – а потом увидеть во всех них общую абстрактную часть, и понять ее смысл через примеры ее частных проявлений.

Я надеюсь, что мои простые объяснения монады ввода-вывода потом помогут вам понять, что такое монады в целом, – я за этот путь.

Простейший ввод-вывод

Итак, вот простейшая программа, которая читает входной текстовый файл, приводит все буквы к верхнему регистру, а потом пишет выходной файл:

main :: IO ()

main = do

contents <- readFile "input.txt"

writeFile "output.txt" (process contents)

process :: String -> String

process s = map toUpper s

Вот, собственно, и все. Видите тут две части программы? Вторая часть для вас должна быть вполне понятна – тут обычная функция process, преобразующая строку в строку. Это действительно обычная функция, никаких побочных эффектов у нее нет и быть не может.

А вот функция main – это как раз та самая часть программы, что отвечает за ввод-вывод, это специфическая функция. В ней мы связываем и именем contents все содержимое файла input.txt, потом преобразовываем это содержимое с помощью функции process, и записываем результат в файл output.txt.

Между двумя этими функциями проходит незримая граница, отделяющая чистый функциональный мир строгих функций без всяких побочных эффектов – от грязного императивного чистилища.

Ну вот, а вы боялись. Усложняйте функцию process, и делайте преобразование файла любой сложности. Проблемы у вас возникнут только тогда, когда потребуется смешивать в лапшу чистые вычисления и взаимодействие с пользователем: если потребуется что-то запросить у пользователя (или прочитать из файла), потом что-то посчитать, потом опять что-то запросить, и так далее. В этом случае – ничего не поделаешь, придется разбираться с кухней.