# Problem: LiberateCase with two or more free variables

Simon Peyton-Jones simonpj@microsoft.com
Wed, 28 Feb 2001 09:15:27 -0800

```| LiberateCase works very nicely as long as there is only one
| variable whose access has to be liberated.  However, already
| with two variables, there are problems.  Given

This is a tough one and I don't understand all the implications of your
example.

|   demandSome :: Int# -> AccessPath -> AccessPath -> Int
|   demandSome n# ap1 ap2  = demandSome' n#
|     where
|       demandSome' n# =
| 	case n# of
| 	  0# -> 1
| 	  n# | n# <# 10# -> I# (accessLen1# ap1) +
|			      demandSome' (n# -# 1#)
| 	  n# | otherwise -> I# (accessLen1# ap2) +
|			      demandSome' (n# -# 1#)

I think the issue is that ap1 is evaluated at one call site and ap2 at the
other, but neither has both evaluated.  Actually, it's not just 'evaluated'
but 'evaluated to exactly the degree that accessLen1 evalutes it'.

I suppose you could try seq-ing with
(accessLen1# ap2) `seq` ...original rhs...

Now that forces ap2 to be evaluated to the right amount in the n<10 branch,
which is I think what you wanted.  In general that's not good because
accessLen may do some real work.

But I wonder why you don't float the constant expression I# (accessLen1#
ap1)
and slly ap2, out of the loop altogether?    Indeed I'm not sure why GHC
doesn't do this:

|   demandSome :: Int# -> AccessPath -> AccessPath -> Int
|   demandSome n# ap1 ap2  = demandSome' n#
|     where
al1 = I# (accessLen# ap1)
al2 = I# (accessLen# ap2)
|       demandSome' n# =
| 	case n# of
| 	  0# -> 1
| 	  n# | n# <# 10# -> al1 +
|			      demandSome' (n# -# 1#)
| 	  n# | otherwise -> al2 +
|			      demandSome' (n# -# 1#)

Simon

```