我有以下代码。
main = print $ sum [1..1000000]
当我跑步时,我得到一个堆栈溢出:
Stack space overflow: current size 8388608 bytes.
Use `+RTS -Ksize -RTS' to increase it.
我习惯于像Python这样的命令式语言,这些算法似乎没有问题:
sum(range(100000000)) # I'm not even using a generator.
4999999950000000
Haskell明显不同,但我不太明白导致堆栈溢出的原因是什么?在Haskell中导致堆栈溢出的问题是什么?
答案 0 :(得分:10)
这整个问题仅与GHC< 7.10有关。在最近的版本中,sum [1..1000000]
在常量空间中工作正常,至少在内置数字类型。
sum
isused to be implemented with the evil foldl
1,它没有那么严格。因此,你从sum
获得的东西本质上是一堆thunk,与你的输入一样大。我认为有一个讨论为什么它在某种程度上以这种方式完成... IMO它基本上只是愚蠢,因为总和通常不能懒得消耗,所以使用strict fold显然是显而易见的。
前奏> :m + Data.List
Prelude Data.List> foldl'(+)0 [1..1000000]
500000500000
1 实际上,foldl
仅用于报告版本......但带累加器的显式递归版本当然不会更好。
答案 1 :(得分:3)
sum
是以foldl
的形式定义的,它以左关联方式延迟,因此在评估单个(在本例中为加法)表达式之前必须为整个列表生成thunk 。
您还可以使用sum
更严格的对应foldl
来定义foldl'
,如下所示:
sum' = foldl' (+) 0
有关foldl
如何为每次计算生成thunks而不能评估任何内容的详细解释,请参阅Foldr. Foldl. Foldl'. from the Haskell Wiki。这将导致堆栈溢出。