52700.fb2
терфейсным он описывает какие в модуле определения, а второй файл называется объектным. Он содержит
скомпилированный код модуля.
Стоит отметить команду runhaskell. Она запускает программу без создания дополнительных файлов.
Но в этом случае выполнение программы будет происходить медленнее.
8.4 Типичные задачи IO
Вывод на экран
Нам уже встретилось несколько функций вывода на экран. Это функции: print (вывод значения из эк-
земпляра класса Show), putStr (вывод строки) и putStrLn (вывод строки с переносом). Каждый раз когда мы
набираем какое-нибудь выражение в строке интерпретатора и нажимаем Enter, интерпретатор применяет к
выражению функцию print и мы видим его на экране.
Из простейших функций вывода на экран осталось не рассмотренной лишь функция putChar, но я думаю
вы без труда догадаетесь по типу и имени чем она занимается:
putChar :: Char -> IO ()
Функции вывода на экран также можно вызывать в интерпретаторе:
Prelude> putStr ”Hello” >> putChar ’ ’ >> putStrLn ”World!”
Hello World!
Обратите внимание на применение постоянной функции для монад >> . В этом выражении нас интересует
не результат, а те побочные эффекты, которые выполняются при композиции специальных функций. Также
мы пользовались функцией >> в сочетании с монадой Writer для накопления результата.
Ввод пользователя
Мы уже умеем принимать от пользователя буквы. Это делается функцией getChar. Функцией getLine мы
можем прочитать целую строчку. Строка читается до тех пор пока мы не нажмём Enter.
Prelude> fmap reverse $ getLine
Hello-hello!
”!olleh-olleH”
Есть ещё одна функция для чтения строк, она называется getContents. Основное отличие от getLine
заключается в том, что содержание не читается сразу, а откладывается на потом, когда содержание дей-
ствительно понадобится. Это ленивый ввод. Для задачи чтения символов с терминала эта функция может
показаться странной. Но часто в символы вводятся не вручную, а передаются из другого файла. Например
если мы направим на ввод данные из-какого-нибудь большого-большого файла, файл не будет читаться сра-
зу, и память не будет заполнена не нужным пока содержанием. Вместо этого программа отложит считывание
на потом и будет заниматься им лишь тогда, когда оно понадобится в вычислениях. Это может существенно
снизить расход памяти. Мы читаем файл в 2Гб моментально (мы делаем вид, что читаем его). А на самом
деле сохраняем себе задачу на будущее: читать ввод, когда придёт пора.
130 | Глава 8: IO
Чтение и запись файлов
Для чтения и записи файлов есть три простые функции:
type FilePath = String
-- чтение файла
readFile
:: FilePath -> IO String
-- запись строки в файл
writeFile
:: FilePath -> String -> IO ()
-- добавление строки в конеци файла
appendFile
:: FilePath -> String -> IO ()
Напишем программу, которая сначала запрашивает путь к файлу. Затем показывает его содержание. За-
тем запрашивает ввод строки из терминала. А после этого добавляет текст в конец файла.