NB: all floats are let-binds, but some non-rec lets
    may be unlifted (with RHS ok-for-speculation)


simplArg:  [use strictness]
	   [used for non-top-lvl non-rec RHS or function arg]
  if strict-type || demanded
	simplStrictExpr
  else
	simplExpr ---> (floats,expr)
	float all the floats if exposes constr app, return expr

simpl (applied lambda)	    ==> simplNonRecBind
simpl (Let (NonRec ...) ..) ==> simplNonRecBind

simpl (Let (Rec ...)    ..) ==> simplRecBind

simplRecBind:
  simplify binders (but not its IdInfo)
  simplify the pairs one at a time
	using simplRecPair

simplNonRecBind:	[was simplBeta]
	[used for non-top-lvl non-rec bindings]
  - check for PreInlineUnconditionally
  - simplify binder, including its IdInfo
  - simplArg
  - if strict-type 
	addCaseBind [which makes a let if ok-for-spec]
    else
	completeLazyBind

simplRecPair:	[binder already simplified, but not its IdInfo]
	  	[used for both rec and top-lvl non-rec]
		[must not be strict/unboxed; case not allowed]
  - check for PreInlineUnconditionally
  - substituteIdInfo and add result to in-scope 
	[so that rules are available in rec rhs]
  - simplExpr --> (floats,expr)
  - float: lifted floats only
	if exposes constructor or pap (even if non-triv args)
	or if top level
  - completeLazyBind
  

completeLazyBind: 	[given a simplified RHS]
	[used for both rec and non-rec bindings, top level and not]
  - try discarding dead
  - try PostInlineUnconditionally
  - let-bind coerce arg and repeat
  - try rhs tylam (float)
  - try eta expand (float)    [not if any float is unlifted && (non-spec || top_lvl || rec)]
  - let-bind constructor args [not if any float is ..as above..]

  - add unfolding [this is the only place we add an unfolding]
    add arity



Right hand sides and arguments
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In many ways we want to treat 
	(a) the right hand side of a let(rec), and 
	(b) a function argument
in the same way.  But not always!  In particular, we would
like to leave these arguments exactly as they are, so they
will match a RULE more easily.
	
	f (g x, h x)	
	g (+ x)

It's harder to make the rule match if we ANF-ise the constructor,
or eta-expand the PAP:

	f (let { a = g x; b = h x } in (a,b))
	g (\y. + x y)

On the other hand if we see the let-defns

	p = (g x, h x)
	q = + x

then we *do* want to ANF-ise and eta-expand, so that p and q
can be safely inlined.   

Even floating lets out is a bit dubious.  For let RHS's we float lets
out if that exposes a value, so that the value can be inlined more vigorously.
For example

	r = let x = e in (x,x)

Here, if we float the let out we'll expose a nice constructor. We did experiments
that showed this to be a generally good thing.  But it was a bad thing to float
lets out unconditionally, because that meant they got allocated more often.

For function arguments, there's less reason to expose a constructor (it won't
get inlined).  Just possibly it might make a rule match, but I'm pretty skeptical.
So for the moment we don't float lets out of function arguments either.


Eta expansion
~~~~~~~~~~~~~~
For eta expansion, we want to catch things like

	case e of (a,b) -> \x -> case a of (p,q) -> \y -> r

If the \x was on the RHS of a let, we'd eta expand to bring the two
lambdas together.  And in general that's a good thing to do.  Perhaps
we should eta expand wherever we find a (value) lambda?  Then the eta
expansion at a let RHS can concentrate solely on the PAP case.
