Jonathan S. Shapiro wrote:
> So the problem in the large is separate compilation, in the sense of
> "separated by an air gap". If we want to support modules written by
> truly unrelated development groups, we need a way to survive colliding
> instances. The only way that I can really see to do that is by using
> lexical scoping, but lexical scoping in the presence of polymorphism
> is a very strange thing.
> 
> The issue is that you have a call to f() that in turn calls g() in
> some other module. Both modules have an instance in scope for (EXAMPLE
> (list char)), but they are not the same instance.
> 
> The question is: which instance should be used in the compilation of
> g()? That is: which lexical environment should be used to decide what
> instance to use? There is truly no right answer to this.

Let's suppose we're dealing with an Eq 'a type class. Suppose f knows
the concrete type of the list it's dealing with, list char. Suppose that
g does not, and handles list 'a.

I would expect the answer is to transitively use whatever instance f
specifies. In other words, the beginning of the call chain where the
type class is first required dominates. I think of type classes as
abstracting vtables, so f is the one building the vtable being passed to
g, so g should be slaved to f.

In pseudo-code:

typeclass Eq 'a with
  eq: 'a -> 'a -> bool

val f: list char -> bool
val g: Eq 'a => list 'a -> 'a bool

(* f builds the vtable passed to g, so the "Eq char" instance
 * in f's scope would seem to be the most straightforward answer.
 *)
let f list = g list '\n'

To be consistent, I think the same reasoning should apply if both f and
g are monomorphic. g is accepting an Eq char from f, so f should specify
the behaviour of Eq char. Hopefully I'm not missing anything obvious.

Sandro

_______________________________________________
bitc-dev mailing list
[email protected]
http://www.coyotos.org/mailman/listinfo/bitc-dev

Reply via email to