我最近一直在使用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。如果我保持事情懒惰,我会得到相同的错误:
为了更好地理解此内容,我重新实现了类似的功能,但没有使用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)
我尝试过对我的foo
函数中的各个部分进行seq
,但这似乎没有帮助。此外,我也尝试使用Control.Monad.Writer.Strict
,但并没有什么改变。
是否需要以某种方式使Sum
在严格意义下执行?或者我完全错了些什么?
注:
- 我可能在术语上有所错误。根据Space leak zoo,我的问题将被归类为“堆栈溢出”,如果是这种情况,我如何将
foo
转换为更迭风格?我的手动递归是否是问题所在? - 阅读Haskell Space Overflow后,我想用
-O2
编译,只是为了看看会发生什么。这可能是另一个问题的话题,但是通过优化,甚至我的seq
'dbar
函数也无法运行。更新:如果我添加-fno-full-laziness
,问题就消失了。
Sum
是一个newtype
,因此它的严格程度或惰性程度与底层类型相同。 - hammar