[Haskell] Probably a trivial thing for people knowing Haskell

Udo Stenzel u.stenzel at web.de
Mon Oct 20 18:44:52 EDT 2008


> Friedrich wrote:
> >Ok to  be more concrete is the laziness "hidden" here?
> >
> >check_line line sum count =  
> >    let match = matchRegex regexp line
> >        in case match of
> >               Just strs -> (sum + read (head strs) :: Integer, count + 1)
> >               Nothing -> (sum, count)

Yes, part of it.  To see why, put yourself into the role of an evaluator
for your program.  An application of check_line will not be evaluated
until necessary, and it becomes necessary only if the result is bound to
a pattern (and that binding is needed for some reason).  At that point,
enough has to be evaluated to determine whether the result is actually a
pair or bottom.

So what will you do?  The body of check_line is a case expression, so
you need to sufficiently evaluate its scrutinee.  You evaluate enough of
matchRegex to see whether the result is Nothing or Just.  Let's say it's
Just.  So you descent into the Just branch, and you see the result is a
pair (and not bottom).  The elements of the pair have not been
evaluated, there was no need to.  Also, the arguments to check_line have
not been evaluated, except for line.

You need to force the evaluation of the elements of the result pair
whenever the pair itself is demanded, for example:

> >check_line line sum count =  
> >    let match = matchRegex regexp line
> >        in case match of
> >               Just strs -> ((,) $! (sum + read (head strs) :: Integer)) $! count + 1
> >               Nothing -> ((,) $! sum) $! count)

(The associativity of ($!) is inconvenient here.  I want
left-associative ($!).  Actually, a strict pair type would be even more
convenient here.)

On recent GHC with bang-patterns, this short-cut works, too.  It's not
quite equivalent, because it will create unevaluated thunks, though they
won't pile up:

> >check_line line !sum !count =  
> >    let match = matchRegex regexp line
> >        in case match of
> >               Just strs -> (sum + read (head strs) :: Integer, count + 1)
> >               Nothing -> (sum, count)


Paul Johnson wrote:
> Try putting turning the "Just" line into something like
> 
>   Just strs -> (seq sum $ sum + read (head strs) :: Integer, seq count 
> $ count + 1)

This doesn't help.  First of all, you don't "try putting" anything
anywhere.  Without understanding what's going on, you'll only create
ugly code, bang your head against a wall and still end up with a space
leak (been there, done that, bought the t-shirt).  Instead, go through
the evaluation by hand and/or use a heap profiler to guide you.  Then
put strictness annotations where needed (and only there).

Putting seqs inside the pair is useless, because the problem is that
nobody will look there to begin with.  Applying seq to sum and count
helps, if done outside the pair constructor, but is not quite right.
You want the new sums to be evaluated strictly, and while making the
function strict in its arguments helps, it stops one step too early.


-Udo

-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
Url : http://www.haskell.org/pipermail/haskell/attachments/20081021/a745bcb0/attachment.bin


More information about the Haskell mailing list