# [Haskell-cafe] memory, garbage collection and other newbie's issues

Andrea Rossato mailing_list at istitutocolli.org
Sun Oct 22 10:06:24 EDT 2006

```Hello Bullat,

first of all, thanks for your lengthy and clear explanation.

On Sun, Oct 22, 2006 at 04:08:49PM +0400, Bulat Ziganshin wrote:
> f a b = let x = a*b
>             y = a+b
>         in x `seq` y `seq` (x,y)
>
> this f definition will not evaluate x and y automatically. BUT its
> returned value is not (x,y). its returned value is x `seq` y `seq` (x,y)
> and when further computation try to use it in any way, it can't put
> hands on the pair before it will evaluate x and y values. are you
> understand?

Yes, I do understand. But, as far as I know, "seq" will just evaluate x
and y enough to see if they are not bottom. So, if x and y are a deep
data structure, they won't be evaluated entirely, right?

That is to say:

> to get real advantage, you need to build your value sequentially in
> monad and force evaluation of each step results:
>
> main = do let x = f 1
>           return \$! x
>           let y = f 2
>           return \$! y
>           let z = f 3
>           return \$! z
>           let a = T x y z
>           ..

...

> > setState ns =
> >     modify (\s -> s {mystate = ns})
>
> here you modify state, but don't ensure that string list is evaluated
> on both levels. well, it will be ok if you ensure evaluation at _each_
> call to this function. alternatively, you can force evaluation before
> assignment by:
>
>  setState ns = do
>      return \$! map length ns
>      modify (\s -> s {mystate = ns})
>

this is the crucial point. You are forcing evaluation with \$! map
length, I'm doing it with writeFile. I do not see very much
difference. That's an ad hoc solution. Since I need to write the
state, instead of (needlessly) looking for the length of it's members,
I write it...;-)

By the way, the problem is not ns, but s, the old state. The new state
has been evaluated by the code below (when we display the number of
lines). So you need to change your code with:

do s <- getState
modify (\s -> s {mystate = ns})

otherwise you are going to have the same space leak as my original
code had. In other word, it is possible to have a user who keeps on
loading files without looking at any line (in this case getState is
never called and so there is no "return \$! mystate s"!).

This produces the same as:
setState ns =
do s <- getState -- that does: return \$ mystate s
liftIO \$ writeFile "/dev/null" s
modify (\s -> s {mystate = ns})

> if StateT is strict monad transformer, this code don't have space
> leaks. you create thunks in two places, in one place you already
> evaluate it, and i wrote what to do in second place.

Yes, indeed. But just because we forced evaluation in a way that `seq`
cannot do. Am I right?

Thanks a lot for you patience. You did help me a lot. And this is not
the first time. I appreciate. Really.
Best regards,
Andrea
```