[Haskell-cafe] help diagnosing space leak with IORef/STRef, just incrementing a million times.
Albert Y. C. Lai
trebla at vex.net
Mon Jan 7 07:35:32 CET 2013
On 13-01-07 12:12 AM, Thomas Hartman wrote:
> I have a space leak in a function that increments a number inside
> IORef or STRef (either lazy or strict).
IORef and STRef operations do not automatically evaluate contents.
"writeIORef r (x + 1)" simply stores a pointer to the expression (thunk)
"x + 1" into the mutable cell. readIORef just reports back a pointer.
modifyIORef just calls readIORef and writeIORef. No evaluation throughout.
"modifyIORef incr" where
incr !x = x + 1
does not make a difference because it is just "writeIORef r (incr x))",
i.e., simply stores a pointer to the expression (thunk) "incr x" into
the mutable cell. The whole process doesn't even care about how many
bangs are in incr.
(It is illuminating to consider how "const True (incr x)" does not
evaluate x. A pointer to True and a pointer to "incr x" are passed to
const, then const throws away the latter without even looking. See also
"const True undefined". One day, you will thank "writeIORef r
undefined"; I certainly did.)
Same for both Data.STRef.Strict and Data.STRef.Lazy. They do not mean
what you think. Here is what they mean:
Data.STRef.Strict means what Control.Monad.ST.Strict means
Data.STRef.Lazy means what Control.Monad.ST.Lazy means
Control.Monad.ST.Strict means that the following hangs:
x = head (runST list) where
list :: ST s [Bool]
list = do {xs <- list; return (True : xs)}
Control.Monad.ST.Lazy means that the above terminates and gives the
answer True.
(Up to this point, same story for Control.Monad.State.Strict and
Control.Monad.State.Lazy.)
I still have not understood Control.Monad.ST.Lazy enough to articulate
its full semantics, but I have some more examples to show what it does:
http://hpaste.org/63925
By understanding what "Lazy" in Control.Monad.ST.Lazy means, you also
see what "Strict" does *not* mean.
In IO or Control.Monad.ST.Strict, use
let y = x+1 in y `seq` write[IO/ST]Ref r y
to expedite the evaluation of x+1. Using the same idea, you may write
your own modify[IO/ST]RefNOW to evaluate while updating.
More information about the Haskell-Cafe
mailing list