当我尝试运行此代码时......
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”。你能解释一下原因吗?最后,我试图弄清楚如何从文件输入创建一个懒惰的文本列表。
答案 0 :(得分:4)
正如Daniel Lyons在评论中提到的那样,这是由于IO和懒惰相互作用。
想象一下,如果你愿意的话:
withFile
打开文件,文件句柄f
。f
内容的Thunk。withFile
关闭文件。HaskellWiki / Maintaining laziness页面上提到了此陷阱。
要修复此问题,您可以在withFile
内阅读整个文件内容(可能强制使用seq
),也可以懒洋洋地关闭文件,而不是使用withFile
。
答案 1 :(得分:1)
我认为是这样的:withFile
在执行函数后关闭文件。 hGetContents
懒惰地读取内容(懒惰的IO),当它需要读取内容时,文件将被关闭。
不要使用withFile
,只需使用openFile
,而不是关闭它。 hGetContents
将在文件读取后将文件置于半封闭状态。或者更好,只需使用readFile