Implict parameters and monomorphism

kahl@heraklit.informatik.unibw-muenchen.de kahl@heraklit.informatik.unibw-muenchen.de
25 Apr 2001 11:28:10 -0000


As a minor point in our draft paper

``From Type Classes to Module Constraints''

http://ist.unibw-muenchen.de/Haskell/ModConstraints/

we argue that implicit parameters and conventional type class contexts
are really the same thing.

This immediately dictated the answers to the first two questions,
and provides guidance for the third:

 > Question 1: can we "inherit" implicit parameters
 > ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 > Consider this:
 > 
 > 	   f x = (x::Int) + ?y
 > 
 > where f is *not* a top-level binding.
 > From the RHS of f we'll get the constraint (?y::Int).
 > There are two types we might infer for f:
 > 
 > 	   f :: Int -> Int
 > 
 > (so we get ?y from the context of f's definition), or
 > 
 > 	   f :: (?y::Int) => Int -> Int
 > 
 > At first you might think the first was better, becuase then
 > ?y behaves like a free variable of the definition, rather than
 > having to be passed at each call site.  But of course, the WHOLE
 > IDEA is that ?y should be passed at each call site (that's what
 > dynamic binding means) so we'd better infer the second.

Wholeheartedly agreed --- the first would break many things.

 > Question 2: type signatures
 > ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 > OK, so is it legal to give an explicit, user type signature to f, thus:
 > 
 > 	   f :: Int -> Int
 > 	   f x = (x::Int) + ?y
 > 
 [...]
 >
 > Conclusion: the above type signature is illegal.  You'll get a message
 > of the form "could not deduce (?y::Int) from ()".

Must be so.


 > Question 3: monomorphism
 > ~~~~~~~~~~~~~~~~~~~~~~~~
 [...] 
 > 
 > Possible choices
 > ~~~~~~~~~~~~~~~~
 > (A) Always generalise over implicit parameters
 >     Bindings that fall under the monomorphism restriction can't
 > 	   be generalised
 > 
 >     Consequences:
 > 	   * Inlning remains valid
 > 	   * No unexpected loss of sharing
 > 	   * But simple bindings like
 > 		   z = ?y + 1
 > 	     will be rejected, unless you add an explicit type signature
 > 	     (to avoid the monomorphism restriction)
 > 		   z :: (?y::Int) => Int
 > 		   z = ?y + 1
 > 	     This seems unacceptable

To me, it seems just as unacceptable as the other type signatures
I have to figure out only because of the monomorphism restriction.

It is, in fact, a logical consequence of the monomorphism restriction.
So as far as the monomorphism restriction is going to be kept,
this is the way to go.

 > (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)
 > 
This is really unacceptable.
Just like the rejected alternatives
in questions 1 and 2, it relies on breaking an otherwise coherent system.

 > (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
 > ~~~~~~~~~
 [...]
 >
 > Choice (C) really says "the monomorphism restriction doesn't apply
 > to implicit parameters".

Precisely.

 > 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'.

Just like anything that is bound to a type with a context.

 > 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.

Indeed, this already is an argument for abolishing the monomorphism
restriction altogether.


Best regards,

Wolfram