Version 4 (modified by john@…, 10 years ago) (diff)

Deriving Instances

Brief Explanation

In Haskell 98, the methods of some basic classes can be created using a deriving clause immediately after a datatype. e.g.

data Color = Red | Yellow | Blue
   deriving (Eq, Ord)

There are some downsides to this. For example, tying the deriving declaration to the datatype:

  • mixes the class system into datatypes (making the report hard to sequentialize), and
  • means that programmers have to decide which classes they are interested in at the point of defining the datatype.

The latter is particularly difficult across module boundaries.

This proposal calls for the point of the deriving declaration to be moved into the class system itself:

  • Derived methods are declared in the class declaration, as a kind of default;
  • Instances are declared using empty (or partial) instance declarations in a way that is already used for default mechanisms.

For example:

class Eq a where
  (==) :: a -> a -> Bool
  (/=) :: a -> a -> Bool
  deriving (==)
  x /= y = not (x == y)

instance Eq Color

The empty (or partial) instance declaration is understood as normal, to define any missing methods using the default declarations in the class declaration. As with other default declarations, derived definition can be overridden in any particular situation if a different notion of equality is required (e.g. to preserve abstractions).

The only real change is that some of the default declarations are provided generically, rather than polymorphically. This shift makes Haskell a little more regular, but it also sets us up nicely for the future if we ever add a mechanism to allow programmers to define generic definitions for their own classes. In H', we would limit ourselves to the existing set of generic definitions that currently can occur in deriving clauses. In a future version of Haskell we may choose to provide a generic programming mechanism whose use would appear in this same place. The design is trying to be relatively future-proof.

Discussion describes an implementation of something very like this in GHC. contains a great discussion of some of these ideas. (NB. Section 3 is misleading: leaving the clauses out of an instance declaration does not leave all the methods undefined; rather it gives the default methods of the class).

As there are only a few fixed methods/classes that can be derived, we may choose not to have any special syntax for the few derived methods, but just put a comment in the code:

class Eq a where
  (==) :: a -> a -> Bool
  (/=) :: a -> a -> Bool
  -- (==) has a magic way of be derived for datatypes 
  x /= y = not (x == y)