Haskell: читать файл построчно - PullRequest
5 голосов
/ 02 марта 2012

Я недавно сделал Waterloo CCC , и я чувствую, что Haskell - идеальный язык для ответа на такие вопросы.Я все еще учусь этому.Однако я немного борюсь с вводом.

Вот что я использую:

import IO
import System.Environment
import System.FilePath

…

main = do
    name <- getProgName
    args <- getArgs
    input <- readFile $
        if not (null args)
            then head args
            else dropExtension name ++ ".in"
    let (k:code:_) = lines input
    putStrLn $ decode (read k) code

Как вы видите, я читаю из командной строки указанный путь к файлуили из j1.in, например, если эта программа называется j1.hs и скомпилирована в j1.

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

Мне интересно, загружает ли readFile весь файл в память,что было бы плохо.Но потом я начал думать, возможно, поскольку Haskell ленив, он читает только первые две строки, потому что это все, о чем он просил позже.Я прав?

Кроме того, если есть что-то с этим примером кода, которое может быть лучше или более идиоматическим, пожалуйста, дайте мне знать.

Ответы [ 4 ]

8 голосов
/ 02 марта 2012

Документация для readFile гласит:

Функция readFile читает файл и возвращает содержимое файла в виде строки. Файл читается лениво, по требованию, как с getContents.

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

Ленивый ввод / вывод - плохая идея для программ с интенсивным вводом / выводом (например, веб-серверов), но он хорошо работает для простых программ, которые не выполняют много операций ввода / вывода.

7 голосов
/ 02 марта 2012

Да, readFile ленив.Если вы хотите быть откровенным об этом, вы можете использовать:

import Control.Monad (replicateM)
import System.IO

readLines n f = withFile f ReadMode $ replicateM n . hGetLine

-- in main
    (k:code:_) <- readLines 2 filename

Это обеспечит закрытие файла как можно скорее.

Но способ, которым вы это сделали, в порядке.

3 голосов
/ 02 марта 2012

readFile читает файл лениво, поэтому он не прочитает весь файл в память, если вы не используете весь файл. Обычно он не читает только первые две строки, поскольку читает в блоках, но читает только столько блоков, сколько необходимо для поиска второй новой строки.

2 голосов
/ 02 марта 2012

Ввод / вывод в Хаскеле обычно не ленив. Однако функция readFile, в частности , является ленивой.

Другие говорили то же самое. Никто еще не заметил, что файл, который вы открыли, не закроется, пока программа не завершится или сборщик мусора не запустится. Это просто означает, что дескриптор файла ОС может оставаться открытым дольше, чем необходимо. В вашей программе это, вероятно, не имеет большого значения Но в более сложном проекте это может быть.

...