如何利用此代码利用Lazy Evaluation?

时间:2011-12-22 15:43:29

标签: haskell 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 个答案:

答案 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”;它通常不赞成,但不需要达到你想要的效果。 (例如,如果你知道readFilegetContents如何运作,那就是懒惰的IO。)

答案 1 :(得分:1)

Haskell作为消费者很懒惰,但不是生产者。 appendFile在输入时是懒惰的,这意味着在生成任何输出之前,它不会等到所有内容都已计算完毕。但是,输出是“严格的”,因为appendFile在整个操作完成之前不会产生执行流。

请注意,如果appendFile使用缓冲或行输出,它将在写入任何内容之前暂停,直到它计算出一块输出。如果禁用缓冲,它必须为你追加的每个字符进行系统调用,这非常慢。