为什么我的Haskell程序总是会耗尽内存?

3
你好,同行们。我决定用Haskell重写一些我以前写过的脚本,只是因为我需要练习和我喜欢这门语言。所以我尝试从一个大约1.7GB的文件中筛选出有兴趣的行,并将剩余的内容写入另一个文件。
我认为Haskell的惰性特性非常适合这个任务,但代码很快就会耗尽内存。之前的版本(C#或Python)采用的是读取行 -> 写入行的方法,但我在这里尝试了不同的方法。我应该重新编写代码以反映先前版本的方法,还是我错过了什么?
所以这是负责原始文件过滤的函数:
getLines :: FilePath -> IO [[String]]
getLines path = do
    text<-readFile path
    let linii=lines text
    let tokens = map words linii
    let filtrate=[x|x<-tokens,length x>7,isTimeStamp (x!!0),isDiagFrame x]
    return filtrate

这个函数负责在新文件中逐行写入文本(尽管我曾试图直接使用writeFile,但失败了):

writeLines ::Handle->[[String]]->IO ()
writeLines handle linii = do
                    let linie=concat $ intersperse " " (head  linii)
                    hPutStrLn handle linie
                    if length linii > 0     then
                                    writeLines handle  (tail linii)
                                        else
                                    print "Writing complete..."

这两个函数是主要的功能,另一个函数负责获取句柄并传递它:

writeTheFile :: FilePath->FilePath->IO ()
writeTheFile inf outf = do
handle<-openFile outf WriteMode
linii<-getLines inf
writeLines handle linii
print "Write Complete"


main = do
arg<-getArgs
if length arg/=2    then
    print "Use like this : trace_pars [In_File] [Out_File] !"
                    else 
    writeTheFile (arg!!0) (arg!!1)

任何建议都将不胜感激...提前致谢

1个回答

14

问题出在这一行:

                    if length linii > 0     then

你正在计算行列表的长度。这意味着整个行列表必须被加载才能进行计数。这意味着你正在读取的整个文件需要被加载到内存中。不好!

解决方案是使用if not . null $ linii then。该null函数检查列表是否为空(只需要加载列表的第一行),而not的行为与您的预期相同。

如果您想要一个更符合习惯用法的writeLines版本(请注意使用FilePath而不是Handle):

writeLines :: FilePath -> [[String]] -> IO ()
writeLines filename = writeFile filename . unlines . map unwords

这个函数与以下代码相同:

writeLines filename lines =
  writeFile filename mergedFile
  where
    mergedFile = unlines mergedLines
    mergedLines = map unwords lines

unlines的作用与intercalate "\n"相同,而unwords的作用与intercalate " "相同。intercalate x的作用与concat . intersperse x相同。

我认为这些信息已经足够让你理解了其中的含义。


谢谢,问题确实是条件的问题。下次会尝试不使用递归来解决。 - omu_negru

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接