Running out of memory in a simple program

Josef Svenningsson josefs@cs.chalmers.se
Fri, 15 Nov 2002 16:57:36 +0100 (MET)


Hmmm, I generally try to avoid using seq. It's a hack and often one can
refrain from using it. Here's how I would solve the problem:

First of all your monad constains an int which is passed around. Typically
we want this to be computed strictly. The way to do this is to add a
strictness annotation. A naive try would be this:

newtype M a = M (Int -> (a,!Int))

Unfortunately we cannot have stricness annotation in this way. So to
achieve this effect we make a new data type for pairs with a strict int:

data PairInt a = P a !Int

Secondly, your bind is lazy. This can be usedful but usually one wants it
to be strict because then we get tail-recursion. The lack of
tail-recursion is the second problem in this example. Strictness is
achieved be converting let to case like this:

  M f >>= k = M $ \i -> case f i of
                          P x i2 ->
                                case k x of
                                  M f2 -> f2 i2

This version doesn't have any problems with spaceleaks. It can now swallow
pretty large numbers, I've tried with 1000000.

I hope this sheds some light on the problem.

	/Josef


On Fri, 15 Nov 2002, Magnus Lindberg wrote:

> Hi again!
> Thanks for your help, Malcolm. I added `seq' at two places to prevent
> laziness and now I never run out of memory.
>
> instance Monad M where
>   return x  = M $ \i -> (x,i)
>   M f >>= k = M $ \i -> let (x,i2) = i `seq' f i
>                             M f2 = x `seq' k x
>                         in f2 i2
>
> (however, I think that just one of the two `seq' should do but if I
> remove any single `seq' then I still run out of memory :(  )
>
> Kind regards
>   Magnus
> _______________________________________________
> Haskell mailing list
> Haskell@haskell.org
> http://www.haskell.org/mailman/listinfo/haskell
>