我正在写一个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"
我有兴趣用延迟评估来解决这个问题
答案 0 :(得分:4)
正如C. A. McCann所说,这应该是懒惰的;但是,appendFile
很可能默认情况下以块缓冲模式打开文件,这意味着在创建行时不会刷新行;相反,数据将一次写入文件几千字节。要解决这个问题,只需滚动自己的功能:
import System.IO
appendFileLines :: FilePath -> String -> IO ()
appendFileLines fileName text =
withFile fileName AppendMode $ \h -> do
hSetBuffering h LineBuffering
hPutStr h text
然后您可以使用appendFileLines
代替appendFile
,并且该文件将一次写入一条记录。
在使用延迟结果执行IO操作方面,您可能会想到的是“懒惰IO”;它通常不赞成,但不需要达到你想要的效果。 (例如,如果你知道readFile
或getContents
如何运作,那就是懒惰的IO。)
答案 1 :(得分:1)
Haskell作为消费者很懒惰,但不是生产者。 appendFile
在输入时是懒惰的,这意味着在生成任何输出之前,它不会等到所有内容都已计算完毕。但是,输出是“严格的”,因为appendFile
在整个操作完成之前不会产生执行流。
请注意,如果appendFile
使用缓冲或行输出,它将在写入任何内容之前暂停,直到它计算出一块输出。如果禁用缓冲,它必须为你追加的每个字符进行系统调用,这非常慢。