Udo Stenzel u.stenzel at web.de
Tue Aug 23 17:08:18 EDT 2005

> I keep getting stack overflows, so I think my code must be too lazy somewhere
> (that's what that means, right?)

Most often, yes.  Afaict, the best way to spot these leaks is to
profiling facilities and getting nothing usable out of it, I don't see a
better way anyway.

In the case of your code, to get at the result, most elements of the
matrix don't need to be known.  They are not evaluated when building the
matrix!  Due to the implicit state they depend on each other, however.
So only when you demand part of the result, is any intermediate state
evaluated at all.

The most elegant way to cure your problem would be a strict state monad.
Unfortunately, there is no such thing (apart from Control.Monad.ST,
which is quite a bit different), you'd have to implement it yourself,
which makes this a silly suggestion.  Also, I'm afraid, a StdGen cannot
be forced easily; it seems to contain some lazyness in its bowels.  I
had no luck when I tried this route.

Something else is possible, though.  Forcing the random numbers in turn
forces the state.  So demand for the arrays must be propagated into
demand for their elements.  randomArray is the right spot to do this.

Simplifying your randomArray a bit, we now use a strict variant of
sequence, and everything works (though it is still dog slow in GHCi).

> randomArray n x = liftM (listArray (1,n)) . sequence' . replicate n
>
> sequence' [] = return []
> sequence' (mx:mxs) = do x  <- mx
>                         xs <- sequence' mxs
>                         x `seq` return (x:xs)

[...]

> tester n = fst \$ runState vals \$ mkStdGen 1
>     where vals = sequence' . repeat \$ randomMatrix n n

tester has the same problem, though diminished by a factor of 100.
Putting a strict sequence here helps again, cutting back on heap usage.
The optimized binary now runs in under 2MiB of memory.

Interestingly, using an unboxed array has almost the same effect.  This
failed, because Matrix couldn't use an unboxed array as well.

Udo.
--
"You see, wire telegraph is a kind of a very, very long cat.  You pull his
tail in New York and his head is meowing in Los Angeles.  Do you understand
this?  And radio operates exactly the same way: you send signals here, they
receive them there.  The only difference is that there is no cat."