LiberateCase and Lambda Dropping

Manuel M. T. Chakravarty chak@cse.unsw.edu.au
Wed, 28 Feb 2001 23:08:58 +1100


LiberateCase would sometimes benefit from lambda dropping.
As an example, consider the definitions

  import PrelGHC
  import PrelBase

  data AccessPath = Cont  AccessPath
		  | Value Int

  accessLen0#, accessLen1#, accessLen2# :: AccessPath -> Int#
  accessLen0# (Value i) = case i of {I# i -> i}
  accessLen1# (Cont ap) = accessLen0# ap
  accessLen2# (Cont ap) = accessLen1# ap

  main = print $ (I# (demandAll 10# (foo 1# ap)))
	 where
	   ap = Cont (Value 10)

  foo 0# x = x
  foo n# x = foo (n# -# 1#) x

and the following two variants of `demandAll'.  The first
one is optimised perfectly by LiberateCase

  demandAll       :: Int# -> AccessPath -> Int#
  demandAll n# ap  = demandAll' n#
		     where
		       demandAll' n# = let
					 v = accessLen1# ap 
				       in
				       case n# of
					 0# -> v
					 n# -> v +# demandAll' (n# -# 1#)

but the second one

  demandAll       :: Int# -> AccessPath -> Int#
  demandAll n# ap  = let
		       v = accessLen1# ap
		     in
		     case n# of
		       0# -> v
		       n# -> v +# demandAll (n# -# 1#) ap

is compiled to the inefficient

  Main.demandAll :: (PrelGHC.Int# -> Main.AccessPath -> PrelGHC.Int#)
  [Constant] __A 2 PS
  Main.demandAll
    = \ n# :: PrelGHC.Int# ap :: Main.AccessPath ->
	  case ap of wild {
	      Main.Value a -> PrelErr.patError @ PrelGHC.Int# lvl_s1Ky;
	      Main.Cont ap1 ->
		  case ap1 of wild1 {
		      Main.Cont a -> PrelErr.patError @ PrelGHC.Int# lvl1_s1Kx;
		      Main.Value i ->
			  case i of wild2 { PrelBase.I# i1 ->
			  case n# of ds {
			      0 -> i1;
			      __DEFAULT -> PrelGHC.+# i1 (Main.demandAll (PrelGHC.-# ds 1) wild)
			  }
			  }
		  }
	  }

Generally, arguments that remain constant in a recursive
function should be lambda dropped, I think.

Cheers,
Manuel

PS: This is not posing a big problem, but it is somewhat
    annoying as I regularly attempt to write the more
    concise form.