Skip main navigation

Type Classes in more Detail

In this article we take a closer look at type classes
Temple silhouet against sunset sky
© University of Glasgow

Type class and instance declarations

Defining type classes

  • A type class is a set of types for which some operations are defined.

  • Haskell has some standard type classes that are defined in the Standard Prelude.

  • You can also define your own.

A type for bright colors

Suppose we’re computing with colors. Here’s a type, and a couple of functions.

 data Bright
= Blue
| Red
deriving (Read, Show)

darkBright :: Bright -> Bool
darkBright Blue = True
darkBright Red = False

lightenBright :: Bright -> Bright
lightenBright Blue = Red
lightenBright Red = Red

A type for milder colors

Now, suppose we have a different type that needs similar functions.


data Pastel
= Turquoise
| Tan
deriving (Read, Show)

darkPastel :: Pastel -> Bool
darkPastel Turquoise = True
darkPastel Tan = False

lightenPastel :: Pastel -> Pastel
lightenPastel Turquoise = Tan
lightenPastel Tan = Tan

Defining a type class

  • Both of our color types have functions to decide whether it’s dark,
    or to lighten it.

  • We can define a class (Color) and its corresponding functions.


class Color a where
dark :: a -> Bool
lighten :: a -> a

This says

  • (Color) is a type class

  • The type variable (a) stands for a particular type that is in the
    class (Color)

  • For any type (a) in (Color), there are two functions you can use:
    (dark) and (lighten), with the specified types.

Defining instances for the type class

  • An (instance) declaration says that a type is a member of a type
    class.

  • When you declare an instance, you need to define the class
    functions.

  • The following says that the type (Bright) is in the class (Color),
    and for that instance, the (dark) function is actually (darkBright).


instance Color Bright where
dark = darkBright
lighten = lightenBright
  • Similarly, we can declare that (Pastel) is in (Color), but it has
    different functions to implement the class operations.

instance Color Pastel where
dark = darkPastel
lighten = lightenPastel

Predefined type classes

Haskell provides several standard type classes. We have a look at two of them: (Num) and (Show).

The Num class

  • (Num) is the class of numeric types.
  • Here is (part of) its class declaration:
 class Num a where
(+), (-), (*) :: a -> a -> a

Num instances

  • There are many numeric types; two of them are (Int) and (Double).

  • There are primitive monomorphic functions that perform arithmetic on
    these types (these aren’t the real names):

addInt, subInt, mulInt :: Int -> Int -> Int
addDbl, subDbl, mulDbl :: Double -> Double -> Double

instance Num Int where
(+) = addInt
(-) = subInt
(*) = mulInt

instance Num Double where
(+) = addDbl
(-) = subDbl
(*) = mulDbl

Hierarchy of numeric classes

  • There are some operations (addition) that are valid for all numeric
    types.

  • There are some others (e.g. trigonometric functions) that are valid
    only for some numeric types.

  • Therefore there is a rich hierarchy of subclasses, including

    • (Integral) — class of numeric types that represent integer
      values, including (Int), (Integer), and more.

    • (Fractional) — class of types that can represent fractions.

    • (Floating) — class containing (Float), (Double), etc.

    • (Bounded) — class of numeric types that have a minimal and
      maximal element.

    • (Bits) — class of types where you can access the representation
      as a sequence of bits, useful for systems programming and
      digital circuit design.

  • If you want to get deeply into numeric classes and types, refer to
    the Haskell documentation.

The Show class

  • We have been using (show) to convert a data value to a string, which
    can then be written to output.

  • Some values can be “shown”, but not all.

  • For example, it is impossible in general to show a function.

  • Therefore (show) needs a type class!

  • [show :: Show, a Rightarrow a rightarrow ,String]

Defining your own Show instance


data Foo = Bar | Baz

We might want our own peculiar string representation:


instance Show Foo where
show Bar = "it is a bar"
show Baz = "this is a baz"

Recall that when you enter an expression (exp) into ghci, it prints
(show exp). So we can try out our strange instance declaration:


*Main> Bar
it is a bar
*Main> Baz
this is a baz

Deriving Show

This is a similar type, but it has a (deriving) clause.


data Foo2 = Bar2 | Baz2
deriving (Read, Show)

Haskell will automatically define an instance of (show) for (Foo2),
using the obvious definition:


*Main> Bar2
Bar2
*Main> Baz2
Baz2

More standard typeclasses

Here is a summary of some of the type classes defined in the standard
libraries.

  • (Num) — numbers, with many subclasses for specific kinds of number.

  • (Read) — types that can be “read in from” a string.

  • (Show) — types that can be “shown to” a string.

  • (Eq) — types for which the equality operator (==) is defined.

  • (Ord) — types for which you can do comparisons like (<), (>), etc.

  • (Enum) — types where the values can be enumerated in sequence; this
    is used for example in the notation ([1..n]) and (‘a’..’z’).


*Main> [1..10]
[1,2,3,4,5,6,7,8,9,10]
*Main> ['a'..'z']
"abcdefghijklmnopqrstuvwxyz"
© University of Glasgow
This article is from the free online

Functional Programming in Haskell: Supercharge Your Coding

Created by
FutureLearn - Learning For Life

Reach your personal and professional goals

Unlock access to hundreds of expert online courses and degrees from top universities and educators to gain accredited qualifications and professional CV-building certificates.

Join over 18 million learners to launch, switch or build upon your career, all at your own pace, across a wide range of topic areas.

Start Learning now