这个Haskell代码会占用太多内存吗?

时间:2011-11-25 23:46:34

标签: haskell tailrecursion-modulo-cons

在此代码中:

import Data.Char
groupsOf _ [] = []
groupsOf n xs = 
    take n xs : groupsOf n ( tail xs )

problem_8 x = maximum . map product . groupsOf 5 $ x
main = do t <- readFile "p8.log" 
      let digits = map digitToInt $concat $ lines t
      print $ problem_8 digits

我意识到在Haskell中,许多程序构造并且似乎存储了一些中间结果,例如上面代码中的groupsOf列表。以上代码是Euler项目问题​​8的参考答案,取自Haskell website。原始问题要求在一个很长的数字链中连续5位数的最大乘积,例如45343231635723421312443535767983456。 因此代码将计算所有产品并将其存储为列表。在其他语言中,我认为它们只会保留一个临时的最大值并丢弃任何较小的值。

groupsOf真的存储了所有中间结果吗?如果问题扩大怎么办?它会分配太多内存吗?

3 个答案:

答案 0 :(得分:12)

不,不是因为groupsOf。那个只需要一次将一个组保留在内存中。但是,maximum可能build up a large thunk因为它懒,所以请确保使用-O-O2进行编译,以便执行严格性分析,或使用foldl1' max代替 1

1 foldl1'位于Data.List

答案 1 :(得分:8)

  

我意识到在Haskell中很多程序构造并且似乎存储了一些中间结果,例如上面代码中的groupsOf列表。

“似乎”在这里说得很好,因为老实说这就是Haskell能够真正发挥作用的地方。事实上,由于懒惰,它可以占用更少的更少内存,而无需您进行复杂的微观管理。

关于惰性IO(例如readFile)的一个很好的事情是,它只会根据需要读取尽可能多的文件,并且在您使用其内容时可以对文件进行垃圾收集。 (好吧,大致如此。这取决于你如何设置缓冲。)

这是一个关于如何执行程序的草图:

t <- readFile "p8.log"

t :: String创建一个thunk。可能检查文件是否存在,并以读取模式打开它。

 let digits = map digitToInt $concat $ lines t

digits :: [Int]

创建一个thunk
 print $ problem_8 digits

一旦我们尝试执行此操作,所有工作都将完成。我们需要对problem_8 digits :: Int进行全面评估才能打印出来。所以我们为problem_8 digits创建了一个thunk并强制它。

maximum . map product . groupsOf 5 $ digits

此时,maximum需要map product . groupsOf 5 $ digits的前两个元素才能看到两者中的哪一个更大。因此,map product需要查看要传递的groupsOf 5 digits的前两个元素。

现在,groupsOf 5需要digits的前5个元素才能生成第一个元素。此时,可能会读取文件的第一行,并完成定义的转换。 groupsOf可以构造它的第一个元素,可能是它的第二个元素(假设该行上有超过6个字符)。 groupsOf 5 digits将前两个元素传递到链上,我们将product映射到这两个元素上,然后maximum检查两者中哪一个更大。我们保留结果,两者中的较大者。

此时(实际上比这一点早一些)我们可以完全丢弃中间结果。 groupOf 5 digits的前两个元素现在完全没必要;我们永远不需要再次检查它们,垃圾收集器可以随时收集它们。该文件的前两个字符也将不再使用,并且可以被丢弃。


现在,这非常手持式,可能稍微不准确。但是你明白了吗? Haskell是懒惰的(技术上Haskell是“非严格的”,通常通过懒惰实现),这使得它的执行风格很多与任何严格的语言不同。这使得我们可以使用看似大量的中间表示和数据结构,而实际占用大量内存。好的编译器,比如GHC,可以像你不相信的那样优化内存使用。

答案 2 :(得分:3)

我不确定你的“中间结果”是什么意思,确切地说......但你的代码看起来很好。具体来说,您groupsOf的实现是tail recursive modulo cons,所以我认为您不必担心堆栈溢出,如果这是您关心的问题。

但是,我可能会误解你的问题。你能澄清一下吗?

相关问题