这个简单的程序在使用ghc:
编译时没有标志的情况下在常量内存空间中运行import Data.List
f x = x*x
g a = foldl' (+) (f a) [1..(1073741824-1)]
main = do putStrLn $ show $ foldl' (+) 0 $ map g [0,1]
使用ghc -O2编译时,内存使用量超过系统资源(8GB)。
将main更改为:
main = do putStrLn $ show $ foldl' (+) 0 [g 0, g 1]
缓解了问题所以它似乎与地图有关。
任何人都可以解释这种行为,也许可以解决这个问题吗?
GHC版本是:格拉斯哥Haskell编译器,版本7.4.1,第2阶段由GHC版本7.4.1启动
答案 0 :(得分:11)
这是完全懒惰的“优化”咬你。当它正常工作时,它可以提供运行时间的渐近改进。当它工作错误时......会发生这种情况。
完全惰性变换将常量移出绑定到封闭范围的常量。在这种情况下,它会获取[1..(1073741824-1)]
常量,并将其移动到封闭范围。但是,这是完全错误的。它导致它在两个调用之间共享,这意味着它无法在第一次有效地流式传输。
除了没有-O2编译外,没有可靠的方法可以打败完整的懒惰转换。
答案 1 :(得分:3)
卡尔解释的原因非常好,我不认为我可以帮助你了。
但我可以告诉你如何解决这个问题。
首先,您g
的确总结为1073741823并添加f a
。
有一个简单的公式可以将数字从1加到n
而没有那么多的加法(据说Gauss在primary-school找到了它):
sumUp :: (Integral a) => a -> a
sumUp n = n * (n+1) `div` 2
用这个你可以写
f x = x*x
g a = sumUp (1073741824-1) + f a
main = do putStrLn $ show $ foldl' (+) 0 $ map g [0,1]
你可以看一下链接,直观地看出为什么这样做或者试着自己找到证据 - 使用归纳法很容易:D