Implict parameters and monomorphism
John Hughes
rjmh@cs.chalmers.se
Wed, 2 May 2001 10:51:58 +0200 (MET DST)
(B) Monomorphism restriction "wins"
Bindings that fall under the monomorphism restriction can't
be generalised
Always generalise over implicit parameters *except* for bindings
that fall under the monomorphism restriction
Consequences
* Inlining isn't valid in general
* No unexpected loss of sharing
* Simple bindings like
z = ?y + 1
accepted (get value of ?y from binding site)
(C) Always generalise over implicit parameters
Bindings that fall under the monomorphism restriction can't
be generalised, EXCEPT for implicit parameters
Consequences
* Inlining remains valid
* Unexpected loss of sharing (from the extra generalisation)
* Simple bindings like
z = ?y + 1
accepted (get value of ?y from occurrence sites)
Discussion
~~~~~~~~~~
None of these choices seems very satisfactory. But at least we should
decide which we want to do.
It's really not clear what is the Right Thing To Do. If you see
z = (x::Int) + ?y
would you expect the value of ?y to be got from the *occurrence sites*
of 'z', or from the valuue of ?y at the *definition* of 'z'? In the
case of function definitions, the answer is clearly the former, but
less so in the case of non-fucntion definitions. On the other hand,
if we say that we get the value of ?y from the definition site of 'z',
then inlining 'z' might change the semantics of the program.
Choice (C) really says "the monomorphism restriction doesn't apply
to implicit parameters". Which is fine, but remember that every
innocent binding 'x = ...' that mentions an implicit parameter in
the RHS becomes a *function* of that parameter, called at each
use of 'x'. Now, the chances are that there are no intervening 'with'
clauses that bind ?y, so a decent compiler should common up all
those function calls. So I think I strongly favour (C). Indeed,
one could make a similar argument for abolishing the monomorphism
restriction altogether.
I disagree.
I think it's important to have a simple model of how many times expressions
are evaluated. Function bodies are clearly evaluated many times, once for each
call, but non-function bindings should be evaluated at most once to respect
call-by-need semantics. Breaking the monomorphism restriction in ANY case
makes both space and time cost of evaluation unpredictable, and brittle when
program changes elsewhere introduce or remove an implicit parameter. It isn't
good enough to say `the chances are' that a program has, for example, linear
time and constant space complexity: the programmer should be able to convince
himself of such properties.
As far as what one would `expect', it's in the very nature of dynamic binding
that it makes the meaning of an expression depend on its context. I for one
would certainly not expect that inlining a definition bound to such an
expression should preserve its meaning! Inlining changes the context, so
`of course' can change the meaning. So I strongly prefer (B)!
John Hughes