Reasons behind the "one instance per type" limitation

Diego Dainese xddainese@xlibero.it
10 Oct 2001 16:21:41 +0200


On Wed, 10 Oct 2001 11:20:43 +1300 Brian Boutel <brian@nzcs.org.nz>
wrote:
> "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.

This roughly what I have in mind: different instances declarations
should be in scope in different modules.

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

Not for sure if we consider as it is used in lisp, but the recently
proposed extension outlined in the paper "implicit parameters: dynamic
scoping with static types" might be more appealing...

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

I'm not sure to understand correctly the 2 alternatives; my proposal
is this: if a function contain a "resolved" overloaded symbol, such as
(+) in

> inc :: Int -> Int
> inc x = x+1

then the instance to use is the one in the scope of the function "inc"
(ad this is included in its clousure); vice versa, if the overloaded
symbol is not resolved, such as in

> inc :: Num a => a -> a
> inc x = x+1

then the instance to use is the one in the scope of the caller of
"inc"; in this case, things look pretty similar to dynamic scope, but
as far as I can tell, is the same as in standard haskell.

I admit I don't have thought deeply about this approach... Are there
some obvious reasons to reject it?

-- 
Diego

To reply remove the 2 `x' from the address.