Multi-parameter type classes are a generalisation of the single parameter type classes, and are supported by some Haskell implementations.

Suppose we wanted to create a 'Collection' type class that could be used with a variety of concrete data types, and supports two operations -- 'insert' for adding elements, and 'member' for testing membership. A first attempt might look like this:

This won't compile, however. The problem is that the 'e' type variable in the Collection operations comes from nowhere -- there is nothing in the type of an instance of Collection that will tell us what the 'e' actually is, so we can never define implementations of these methods. Multi-parameter type classes solve this by allowing us to put 'e' into the type of the class. Here is an example that compiles and can be used:

A problem with the above example is that, in this case, we have extra information that the compiler doesn't know, which can lead to false ambiguities and over-generalised function signatures. In this case, we can see intuitively that the type of the collection will always determine the type of the element it contains - so if c is [a], then e will be a. If c is Hashmap a, then e will be a. (The reverse is not true: many different collection types can hold the same element type, so knowing the element type was e.g. Int, would not tell you the collection type).

In order to tell the compiler this information, we add a functional dependency, changing the class declaration to

Example: A functional dependency

class Eq e => Collection c e | c -> e where ...

A functional dependency is a constraint that we can place on type class parameters. Here, the extra | c -> e should be read 'c uniquely identifies e', meaning for a given c, there will only be one e. You can have more than one functional dependency in a class -- for example you could have c -> e, e -> c in the above case. And you can have more than two parameters in multi-parameter classes.

After all, nothing is stopping someone from coming along later and adding another instance:

Example: A nonsensical instance of Mult

instance Mult Matrix Matrix (Maybe Char) where
{- whatever -}

The problem is that c shouldn't really be a free type variable. When you know the types of the things that you're multiplying, the result type should be determined from that information alone.

You can express this by specifying a functional dependency:

Example: The correct definition of Mult

class Mult a b c | a b -> c where
(*) :: a -> b -> c

This tells Haskell that c is uniquely determined from a and b.

At least part of this page was imported from the Haskell wiki article Functional depedencies, in accordance to its Simple Permissive License. If you wish to modify this page and if your changes will also be useful on that wiki, you might consider modifying that source page instead of this one, as changes from that page may propagate here, but not the other way around. Alternately, you can explicitly dual license your contributions under the Simple Permissive License.