To go back to the debate on instances, here is a concrete proposal for handling
instances in Haskell 1.3:
1) A C-T instance can be defined in any module in which C and T are in scope.
2) A C-T instance defined in module M is in scope in every module which
imports from M, directly or indirectly. (If C or T are not in scope, a
module just passes the instance on in its interface).
3) A C-T instance may be imported more than once via different routes,
provided that the module of origin is the same.
4) If an application of an overloaded function is resolved locally, the
relevant instance must be in scope.
5) There must be at most one C-T instance defined in the collection of
modules which make up any one program (global resolution occurs in Main).
This retains the Global Instance Property, except that instead of instances
having universal significance over all programs, they have global significance
over any one program. An instance can be redefined by replacing one module by
another. There is still no easy way to redefine Prelude instances, except
perhaps by selective inclusion of individual Prelude modules, but you can
define instances for Prelude types which don't already have them.
These rules for overloaded functions and instances seem to me to be closely
analogous to polymorphic functions and types. If an application of a
polymorphic function is resolved locally, the relevant type must be in scope.
If globally, it may be applied to any type defined in the program as a whole.
------------
There is a small related issue. It is highly desirable (whether the instance
rules are changed or not) to be able to tell from an interface file which
original module an instance was defined in. Current rules and practice seem
not to allow for this. You see interfaces such as:
interface M1 where interface M3 where
import M2 (C(..)) or import M2 (C(..))
import M3 (T(..)) data T = ...
instance C T instance C T
... ...
In either case, you can't tell whether the instance is defined in M2 or M3.
I would like to see the origin of instances in interface files. My preference
from an implementers point of view would be something like:
interface M1 where interface M3 where
import M2 (C(..)) or import M2 (C(..))
import M3 (T(..),fT) type T = ...
instance C T where f = fT instance C T where f = fT
The name fT is invented while compiling M3 and passed around in interface
files, but not exported from them into implementation modules. As well as
specifying the origin of the instance, it gives the code generator something
to link to. The report already allows types to be imported into an interface
but not exported into the implementation module (5.3.2, para 4), so it is not
much of a stretch to do the same for functions.
------------
By the way, there is another situation where interfaces seem insufficient.
There is no official ruling on whether the original names of constructors or
class methods should be specified in an interface. For example, given:
module M1 where
data T = A | B
...
module M2 (M1..) where
import M1 (T(..), ...) renaming (B to C)
the following interface for M2 is possible:
interface M2 where
import M1 (T(..), ...) renaming (B to C)
data T = A | C
The constructor has been renamed, but you can't tell that from the interface.
(Some compilers even leave the renaming clause out.) It is true that a
compiler can manage on this information alone, but it is poor documentation on
what has happened. I think that the standard should insist that renaming be
explicit in interfaces). This can be done with current syntax, eg:
interface M2 where
import M1 (T(A,B), ...) renaming (B to C)
data T = A | C
However, it would be safe to allow, in interface files only, an import to
specify a subset of the constructors (at least those that are renamed). The
full set appears later anyway. All this applies to class methods as well.
Ian [EMAIL PROTECTED], Tel: 0272 303334