Reasons behind the "one instance per type" limitation

Brian Boutel brian@nzcs.org.nz
Wed, 10 Oct 2001 11:20:43 +1300


"Iavor S. Diatchki" wrote:
> 
> hello,
> 
> > Why aren't instance declarations handled by the module system like
> > every other symbol, so that a module can decide when to import an
> > instance declaration and when to export it? Are there technical
> > difficulties with this approach?
> 
> i beleive the reason is that instances don't  have names and the
> module system deals with names.  on the other hand i don't think
> this is a very good reason and completely agree with you that
> it is a problem.  i think some work is being done on introducing
> named instances to Hasekll (there was a paper in the Haskell workshop
> i think).

This is actually quite messy. The first point that needs to be made is
that instance code is invoked silently. Writing x==y invokes instance
code, but there is no way to say which instance should be used, so it is
important that there is precisely one instance declaration in scope for
that class and type. The current definition of Haskell achieves this by
insisting that there is only one such declaration on the whole progam,
although earlier versions achieved it by more complex, and less
convenient rules, that had the advantage that they could be checked
locally, at module compile time. One could envisage other means, such as
defining, by some new syntactic feature, which of the possible (named)
instance declarations was to be used in a particular scope.

Having different instance definitions in scope at different places can
casue problems, as code would just use whichever was in scope where it
was invoked. This is like the dynamic scope rules of early Lisp, which
is not considered good design. An alternative is to treat instances as
part of the static environment at declaration time, and include them in
closures when functions are passed around or exported. This ensures that
a named function always uses the same instance code for the same type,
but still has problems. In a language with referential transparency, one
should be able to replace a function call by its body code, with
substitution of arguments, (I'm assuming top-level functions with no
global variables). Instances behave like global variables, so calling an
imported function which brings its instances with it will in general
give different results from substitution of body code for the function,
and getting whichever instance is in scope at the point of call.
Personally, I don't like this prospect.

--brian