Puzzled, once again. I think I reason too operationally about these
things. It's a curse brought on by being brain-damaged by Basic
programming at an early age.
John Peterson writes:
The issue is at what point is the overloading of trouble, which would
be typed as
trouble :: Problematic a => a -> a
is resolved to a concrete type. There are two different instances supplied
to resolve Problematic(Int): one in module Two and another in module
Three.
OK so far.
If the signature
trouble :: Int -> Int
is placed in module Two then the assumption is that the instance in
module Two is used. However, if the overloading is resolved in Three,
the other definition is used. What is important is the definition of
Problematic(Int) in force when the type checker encounters this
context during type checking. The added type signature forces this to
happen in Two; without the signature this happens in Three.
The added type signature does indeed force type checking in Module
Two, where as this can (but need not necessarily be) put off until
module Three without it. However, is this the only criterion for when
the overloading is resolved? My operational brain gives me two
choices:
1) Build the resolution dictionary using the context of Module Two
(the point of declaration)
2) Build the resolution dictionary using the context of Module Three
(the point of use).
To me, this is orthogonal from when the actual type checking occurs.
Choice 1 is my preference: it allows the writer of trouble to
anticipate the meaning of his or her function using the context in
which it is created. This is a little constraining; given this rule,
a new instance could not be written (say in module 3) and then trouble
called with a value of this new instance type.
Thus, this is at least connected to type checking (and thus not
completely orthogonal, as I stated above). Choice 1 dictates the
seemingly paradoxical situation where a user could write an instance
for Problematic for, say, Float and immediately have the call to
trouble fail on a type error, even though the type of trouble is
(Problematic a) => a -> a. This is a nastiness that I am prepared to
live with for the sake of controlability; it forces the new instance
to be placed in a module inherited by both Module a and Module b.
Currently, the C-T rule ensures that only one instance for a given
type - class pair exists and that this instance is visible wherever
both the class and type are in scope.
Indeed; this makes the choice trivial.
Allowing multiple instances (as in Phil's example) presents no
implementation problems; the issue is entirely one of choosing either
the current semantic simplicity and rigidity or a more flexible system
with more complex semantics. Personally, I would choose the
latter!
And this I both understand and agree with.
Dave Barton
[EMAIL PROTECTED]