Type classes

A type class is similar to an interface which describes what an implementing type should do. They can then be used to overload functions which require certain properties. For example, types which are members of the Num type class can be used with mathematical operators. This can be seen in the in the multiplication operator, (*), has type (Num a) => a -> a -> a. Num a is called the class constraint.

Defining type classes

Type classes are defined with the class keyword. The members of the Eq type class define the == operator for equality. The Eq type class is defined as below.

class Eq a where
    (==) :: a -> a -> Bool

Instance declarations

Type classes can be implemented using the instance keyword.

instance Eq Bool where
    True  == True  = True
    False == False = True
    _     == _     = False

Common type classes

  • Num - Numeric. Provides standard mathematical operators.

  • Eq - Equality. Provides the equality and inequality operators.

  • Ord - Orderable. Provides the greater and less than operators for types which can be ordered.

  • Read - Read instances define how to convert a String to a type.

  • Show - Show instances define how to convert a type to a String.

  • Integral and Floating provide the div and (/) operators respectively.

  • Enum - Defines several functions for enumerable types such as succ and toEnum.

Deriving type class instances

Defining instances for type classes such as Eq, Ord and Show usually have a straightforward implementation for any type. The deriving keyword tells the compiler to derive the type class instances itself. For example data Maybe a = Nothing |Just a deriving (Eq, Ord) will derive Eq and Ord instances for Maybe automatically.

Subtypes

Consider the type data Point a = Point { x :: a, y :: a}. In order to Show a Point its values also have to implement Show. When defining the Show instance for Point, a Show constraint is put on the values.

instance Show a => Show (Point a) where
    show (Point x x) = "(" ++ show x + ", " ++ show y ++ ")"

It is also possible to enforce that every instance of a type class is already an instance of another. Ord members must already be members of Eq.

class Eq a => Ord a where
    ...