我最近一直在玩 Writer Monad,我遇到了似乎是空间泄漏的问题。我不能说我完全理解这些事情,所以我想知道这里发生了什么,以及如何解决它。
首先,这是触发此错误的方法:
import Control.Monad.Writer
import Data.Monoid
foo :: Integer -> Writer (Sum Integer) Integer
foo 0 = return 0
foo x = tell (Sum x) >> foo (pred x)
main = print $ runWriter $ foo 1000000
我得到:
Stack space overflow: current size 8388608 bytes.
Use `+RTS -Ksize -RTS' to increase it.
为了更好地理解这一点,我在没有 Writer 或 Sum 的情况下重新实现了类似的功能,如果我保持良好和懒惰,我会得到同样的错误:
bar :: Integer -> (Integer, Integer)
bar x = bar' 0 x
where bar' c 0 = (0, c)
bar' c x = bar' (c + x) (pred x)
但我可以通过添加seq
等式来解决这个问题:
bar' c x = c `seq` bar' (c + x) (pred x)
我已经尝试seq
了我的foo
功能的各个部分,但这似乎没有帮助。另外,我尝试过使用Control.Monad.Writer.Strict
,但这也没有什么不同。
Does Sum
need to be strict somehow? Or am I missing something
completely different?
Notes
- I may have my terminology wrong here. According to Space leak
zoo, my problem would be classified as a 'stack overflow', and if
that's the case, how would I convert
foo
to a more iterative style? Is my manual recursion the problem? - After reading Haskell Space Overflow, I had
the idea to compile with
-O2
, just to see what happens. This may be a topic for another question, but with optimizations, even myseq
'dbar
function fails to run. Update: This issue goes away if I add-fno-full-laziness
.