Solution to the monomorphism restriction/implicit parameter
problem
Ben Rudiak-Gould
benrg@dark.darkweb.com
Mon, 4 Aug 2003 23:31:03 -0700 (PDT)
Complications:
* In my examples it's easy to tell whether all uses of the implicit
parameter refer to the same explicit binding, but it may be difficult
when recursion is involved. This problem has already arisen in the
case of type class constraints, and has been solved, so I'm confident
it can be solved for implicit parameters too. Unfortunately, the two
cases are not quite the same:
f :: (Num a) => a -> b
f x = f (x+1)
g :: (?x :: Int) -> b
g = g {?x = ?x+1}
Here all calls of f use the same implicit argument, but calls of g use
different ones.
* It might be harder to pre-apply the implicit value if it's not in
scope at the early application point, as in:
let g = ?x in ([deeply nested expr...] let ?x = [...] in g)
But referential transparency means that it can always be done; it's
just tricky.
* It's not really necessary for safety that all uses of the implicit
parameter refer to the same explicit binding; they just need to refer
to the same value. So this could be accepted:
let ?x = 1 in (let g = ?x in (g, let ?x = 1 in g))
even though it would be rejected if one of the 1s were changed to
something else. Cases like this would be rare, though, and it's not
clear that programs of this type should really be accepted anyway,
since the safety is rather fragile.
None of these complications threatens the overall validity of the
monomorphism restriction, because the algorithm on which the monomorphism
restriction is based is heuristic anyway: the only requirement is that
when it says a reduction is safe, it mustn't be wrong. If the complicated
cases end up being too complicated, it's perfectly acceptable to give up
and say they're unsafe.
This one is a slightly different story:
* Pre-application might introduce space leaks. My intuition says to
ignore this issue, because (1) let-abstraction always has the
potential of introducing space leaks, and (2) Even if you explicitly
write something like "length [1..1000000] + length (tail [1..1000000])"
the compiler is allowed to combine the two lists without telling you,
even though this introduces a space leak.
-- Ben