为什么我的haskell程序内存不足?

omu*_*gru 3 file-io haskell functional-programming

你好编码员.所以我决定重写我在haskell里躺着的一些旧脚本,因为我需要练习,我喜欢这种语言.所以在这里我试图过滤一个巨大的文件(大约1.7 GB),削减不感兴趣的行,并将剩余的东西写在另一个文件中.

我认为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
Run Code Online (Sandbox Code Playgroud)

这个人负责在新文件中一次写一行(尽管我试图直接使用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..."
Run Code Online (Sandbox Code Playgroud)

这两个是主要功能,另一个负责手柄和传递它:

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)
Run Code Online (Sandbox Code Playgroud)

任何建议都将非常感谢...提前感谢

dfl*_*str 14

这里的问题是这一行:

                    if length linii > 0     then
Run Code Online (Sandbox Code Playgroud)

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

解决方案是使用if not . null $ linii then.该null函数检查列表是否为空(仅强制列表的第一行加载),并且not行为与您期望的一样.

如果你想要一个更惯用的版本writeLines(注意使用FilePath而不是Handle):

writeLines :: FilePath -> [[String]] -> IO ()
writeLines filename = writeFile filename . unlines . map unwords
Run Code Online (Sandbox Code Playgroud)

此功能与以下内容相同:

writeLines filename lines =
  writeFile filename mergedFile
  where
    mergedFile = unlines mergedLines
    mergedLines = map unwords lines
Run Code Online (Sandbox Code Playgroud)

unlinesintercalate "\n"和,unwords是一样的intercalate " ".intercalate x是一样的concat . intersperse x.

我认为这应该足以让您了解正在发生的事情.