£199.99 £139.99 for one year of Unlimited learning. Offer ends on 28 February 2023 at 23:59 (UTC). T&Cs apply

# Type Classes in more Detail

In this article we take a closer look at type classes
© 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 -> IntaddDbl, 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 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