3

当我尝试运行此代码时...

module Main where

import qualified Data.Text.Lazy.IO as LTIO
import qualified Data.Text.Lazy as LT
import System.IO (IOMode(..), withFile)

getFirstLine :: FilePath -> IO String
getFirstLine path =
        withFile path ReadMode (\f -> do
                contents <- LTIO.hGetContents f
                return ("-- "++(LT.unpack . head $ LT.lines contents)++" --"))

main::IO()
main = do
        firstLine <- getFirstLine "/tmp/foo.csv"
        print firstLine

我明白了

"-- *** Exception: Prelude.head: empty list

...我希望它打印“/tmp/foo.csv”的第一行。你能解释一下为什么吗?最终,我试图弄清楚如何从文件输入中创建一个惰性文本列表。

4

2 回答 2

4

正如 Daniel Lyons 在评论中提到的,这是由于 IO 和惰性交互。

想象一下,如果你愿意:

  • withFile打开文件,到文件句柄f.
  • 使用内容的 Thunkf返回。
  • withFile关闭文件。
  • Thunk 被评估。关闭的文件中没有内容。

HaskellWiki / 维护懒惰页面上提到了这个陷阱。

要修复,您可以读取其中的整个文件内容withFile(可能通过强制使用seq)或懒惰地关闭文件而不是使用withFile.

于 2012-08-17T20:56:26.760 回答
1

我认为是这样的:withFile执行函数后关闭文件。hGetContents延迟读取内容(延迟 IO),当它需要读取内容时,文件已关闭。

不要使用withFile,而是尝试使用openFile,而不是关闭它。hGetContents读取文件后会将文件置于半关闭状态。或者更好,只需使用直接读取内容readFile

于 2012-08-17T20:56:14.930 回答