这是我在控制台中得到的:
ghci> sum $ takeWhile (<10000000) [1..]
49999995000000
(11.96 secs, 2174569400 bytes)
超过2GB!我想这sum
可以丢弃它已经求和的任何东西。你会怎么写这个?
这是我在控制台中得到的:
ghci> sum $ takeWhile (<10000000) [1..]
49999995000000
(11.96 secs, 2174569400 bytes)
超过2GB!我想这sum
可以丢弃它已经求和的任何东西。你会怎么写这个?
您正在创建一千万个Integer
s 和许多列表单元格。此外,您正在运行解释代码,如果您通过编译器运行它,那将在一定程度上减少分配。
主要问题是解释器根本没有优化,因此sum
使用了构建巨大thunk 的惰性变体。sum
丢弃它已经消耗的列表部分就好了,但它用一个 thunk 替换它以随后计算结果,所以
sum [1,2,3,4 ...]
变成
(...((((0 + 1) + 2) + 3) + 4) + ...)
之后。这不是最佳替换,因为Integer
s 的添加是严格的。
在 ghci 提示符下,你应该写
Prelude Data.List> foldl' (+) 0 $ takeWhile (< 10000000) [1 .. ]
49999995000000
(1.41 secs, 1443355832 bytes)
解决这个问题。在一个编译好的(当然是优化的)程序中,sum
可以正常工作。
这看起来与http://www.haskell.org/haskellwiki/Memory_leak中描述的完全一样
所以这里的解决方案可能是foldl' (+) 0 $ takeWhile (<10000000) [1..]
(需要import Data.List
)。
可能有一个更好的解决方案,因为我只是一个 Haskell 新手并且也很好奇。=^.^=(编辑:请阅读下面的第一条评论:-P)