Как воспользоваться Lazy Evaluation с этим кодом?
Я пишу программу на Haskell, в которой я хочу записать в уже существующий файл. Программа должна генерировать каждую строку перед добавлением ее в файл. Поэтому вместо того, чтобы сначала выполнять все вычисления, а затем добавлять их в файл, я бы хотел, чтобы программа добавляла каждую строку по мере ее вычисления.
Вот код, который я пытался:
-- line in my do-notation of interet
-- filename = valid filename
-- records = list of record data types
appendFile fileName (map recordToString records)
recordToString :: Record -> String
recordToString r = club r ++ "," ++ mapName r ++ "," ++ nearestTown r ++ "," ++ terrain r ++ "," ++ mapGrade r ++ "," ++ gridRefOfSWCorner r ++ "," ++ gridRefOfNECorner r ++ "," ++ expectedCompletionDate r ++ "," ++ sizeSqKm r ++ ",\n"
Я заинтересован в решении этой проблемы с ленивой оценкой
2 ответа
Как сказал К. Макканн, это должно быть уже лениво; тем не мение, appendFile
скорее всего по умолчанию откроет файл в режиме с блочной буферизацией, что означает, что строки не будут очищены при их создании; вместо этого данные будут записываться в файл по несколько тысяч байт за раз. Чтобы решить эту проблему, просто наведите свою собственную функцию:
import System.IO
appendFileLines :: FilePath -> String -> IO ()
appendFileLines fileName text =
withFile fileName AppendMode $ \h -> do
hSetBuffering h LineBuffering
hPutStr h text
Тогда вы можете использовать appendFileLines
вместо appendFile
и файл будет записан в одну запись за раз.
То, о чем вы, возможно, думаете, с точки зрения выполнения операций ввода-вывода с ленивыми результатами, называется "ленивый ввод-вывод"; на него обычно нахмурились, но для достижения желаемого эффекта здесь не обязательно. (Если вы знаете, как readFile
или же getContents
работать, например, это ленивый IO.)
Haskell ленив как потребитель, но не как производитель. appendFile
ленив при вводе, то есть он не ждет, пока весь ваш контент будет рассчитан, прежде чем производить какие-либо выходные данные. Тем не менее, это "строго" на выходе, в том appendFile
не выдаст поток выполнения, пока вся операция не будет завершена.
Обратите внимание, что если appendFile
использует буферизованный или линейный вывод, он будет задерживать запись чего-либо до тех пор, пока не вычислит часть вывода. Если буферизация отключена, она должна сделать системный вызов для каждого добавляемого вами символа, что очень медленно.