I've been playing with the Writer Monad recently, and I've run into what appears to be a space leak. I can't say I fully understand these things yet, so I'd like to know what's happening here, and how to fix it.
First, here's how I can trigger this error:
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
I get:
Stack space overflow: current size 8388608 bytes.
Use `+RTS -Ksize -RTS' to increase it.
To understand this better, I've reimplemented similar functionality without Writer or Sum, and if I keep things nice and lazy, I get the same error:
bar :: Integer -> (Integer, Integer)
bar x = bar' 0 x
where bar' c 0 = (0, c)
bar' c x = bar' (c + x) (pred x)
But I can remedy this by adding seq
to the equation:
bar' c x = c `seq` bar' (c + x) (pred x)
I've tried seq
ing various bits of my foo
function, but that doesn't seem
to help. Also, I've tried using Control.Monad.Writer.Strict
but that
doesn't make a difference either.
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
.
Sum
is anewtype
so it's as strict or lazy as the underlying type. – Backpedal