Returning to the perennial discussion of how and whether to
extend Haskell type classes as advocated by Gavin Wraith, Yuli
Zhou and others...
Several people have found that multi-parameter classes are useful in
Gofer. While there are some aspects of the Gofer design which would be
problematic in Haskell (overlapping instances would cause additional
incoherency and probably lose principal types due to interaction with
context simplification), a conservative extension would be fairly
straightforward, and hopefully non-controversial.
Suggestion, allow:
class context => C a_1 ... a_k where
...
instance context => C (t_1 ... t_k) where
...
Existing Haskell rules still apply. In particular, the t_i must
be of the form
T a_1 ... 1_n
This avoids problems due to overlapping instances.
The rules for this are quite simple to state. I have written them
down as a simple variation on our ESOP paper. I don't have principal
types, soundness or completeness results but these shouldn't be
significantly different from the standard results.
Both documents are available from ftp.dcs.glasgow.ac.uk [130.209.240.50]
pub/glasgow-fp/tech_reports/FP-94-01:type-classes-in-haskell.ps.Z
[Extended version of the ESOP paper]
pub/glasgow-fp/authors/Kevin_Hammond/multi-param-type-classes.ps.Z
[Mac PostScript -- warning: may not print!]
Care does need to be taken when defining methods. For example,
(+) :: (Num a, Num b, Num c) => a -> b -> c
may seem to be useful, but will often require default types or
type signatures to disambiguate!
There may also be problems with partial applications. For example,
given the above type for (+) and two instances
(+) :: Int -> Int -> Int
(+) :: Int -> Float -> Float
then (+) (1::Int) could be either (Int->Int) or (Int->Float).
My rules would disallow this.
The rules also prevent the introduction of ambiguities through, e.g.
(+) :: Int -> Int -> Int
(+) :: Int -> Int -> Float
That is, the result type is uniquely determined by the argument
types.
The main implementation problem is extending instance lookup to cover
multiple type constructors. The prototype Glasgow compiler was
designed to allow this, and I believe hbc also does this (as well as
Gofer, of course), so it's not a big issue!
Does this buy enough to be worth proposing for Haskell 1.3?
Kevin