10

这是我在控制台中得到的:

ghci> sum $ takeWhile (<10000000) [1..]
49999995000000
(11.96 secs, 2174569400 bytes)

超过2GB!我想这sum可以丢弃它已经求和的任何东西。你会怎么写这个?

4

2 回答 2

13

您正在创建一千万个Integers 和许多列表单元格。此外,您正在运行解释代码,如果您通过编译器运行它,那将在一定程度上减少分配。

主要问题是解释器根本没有优化,因此sum使用了构建巨大thunk 的惰性变体。sum丢弃它已经消耗的列表部分就好了,但它用一个 thunk 替换它以随后计算结果,所以

sum [1,2,3,4 ...]

变成

(...((((0 + 1) + 2) + 3) + 4) + ...)

之后。这不是最佳替换,因为Integers 的添加是严格的。

在 ghci 提示符下,你应该写

Prelude Data.List> foldl' (+) 0 $ takeWhile (< 10000000) [1 .. ]
49999995000000
(1.41 secs, 1443355832 bytes)

解决这个问题。在一个编译好的(当然是优化的)程序中,sum可以正常工作。

于 2013-01-12T23:25:50.857 回答
6

这看起来与http://www.haskell.org/haskellwiki/Memory_leak中描述的完全一样

所以这里的解决方案可能是foldl' (+) 0 $ takeWhile (<10000000) [1..](需要import Data.List)。

可能有一个更好的解决方案,因为我只是一个 Haskell 新手并且也很好奇。=^.^=(编辑:请阅读下面的第一条评论:-P)

于 2013-01-12T23:25:03.290 回答