52700.fb2 Учебник по Haskell - читать онлайн бесплатно полную версию книги . Страница 140

Учебник по Haskell - читать онлайн бесплатно полную версию книги . Страница 140

main = msg1 >> getLine >>= read >>= append

where read

file = readFile file >>= putStrLn >> return file

append file = msg2 >> getLine >>= appendFile file

msg1

= putStr ”input file: ”

msg2

= putStr ”input text: ”

В самом левом вызове getLine мы читаем имя файла, затем оно используется в локальной функции

read. Там мы читаем содержание файла (readLine), выводим его на экран (putStrLn), и в самом конце мы

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

будем читать новые записи и добавлять их в файл. Новая запись читается функцией getLine в локальной

функции append.

Сохраним в модуле File. hs и посмотрим, что у нас получилось. Перед этим создадим в текущей дирек-

тории тестовый пустой файл под именем test. В него мы будем добавлять новые записи.

*Prelude> :l File

[1 of 1] Compiling File

( File. hs, interpreted )

Ok, modules loaded: File.

*File> main

input file: test

input text: Hello!

*File> main

input file: test

Hello!

input text: Hi)

*File> main

input file: test

Hello!Hi)

В самом начале наш файл пуст, поэтому сначала мы видим пустую строчку вместо содержания, но потом

мы начинаем добавлять в него новые записи.

Ленивое и энергичное чтение файлов

С чтением файлов связана одна тонкость. Функция readFile читает содержимое файла в ленивом стиле.

Подробнее о ленивой стратегии вычислений мы поговорим в следующей главе. По ка отметим, что readFile

не читает следующую порцию файла до тех пор пока она не понадобится в программе. Иногда это очень удоб-

но. Например мы можем читать содержание очень большого файла и составлять какую-нибудь статистику

на основе прочитанного текста. При этом в памяти будет храниться лишь малая часть файла. Но иногда

это свойство мешает. Рассмотрим такую задачу: перевернуть текст в файле под именем ”test”. Мы должны

сначала считать текст из файла, затем перевернуть его и в конце записать в тот же файл. Мы могли бы

написать эту программу так:

module Main where

main :: IO ()

main = inFile reverse ”test”

inFile :: (String -> String) -> FilePath -> IO ()

inFile fun file = writeFile file . fun =<< readFile file

Типичные задачи IO | 131

Функция inFile обновляет текст файла с помощью некоторого преобразование. Но если мы запустим эту

программу:

*Main> main

*** Exception: test: openFile: resource busy (file is locked)