> module TypeClasses where
A type class is an interface that defines some behavior.
We saw the Show
type class that contains one method show
that allows printing of expressions:
class Show a where
show :: a -> String
The function show
is special because it is used by ghci
to print the result of our computations.
Another commonly used class is the one that defined equality:
class Eq a where
(==) :: a -> a -> Bool
(/=) :: a -> a -> Bool
The above class definition defines two methods, equality (==)
and inequality (/=)
. _Question:_What is the type of the equality operator (==)
?
The type of a class method (here, the equality operator (==)
) is
(==) :: (Eq a) -> a -> a -> Bool
This means that equality can be used to any type that satisfies the type class constraint Eq
, i.e., any type that instantiates the class Eq
.
Haskell has many build-in instances of Eq
, for example, Integers
are one such instance. Thus, checking equality of integers is OK:
1 == 3 = False
Type class constraints are propagated. Thus any function that uses equality check, also has the equality type class constraint:
> checkEq :: (Eq a) => a -> a -> String
> checkEq x y = if x == y then "Equal" else "Not Equal"
Remember our old friend, the Err
data type?
> data Err a = Value a | Error a deriving (Show)
If we try to show
an Err
value, we will get an awful type error
No instance for (Show (Err a0)) arising from a use of ‘show’
To fix this error we need to make Err
an instance of the class Show
. There are are two ways to go.
data Err a = Value a | Error a deriving (Show)
Haskell has a mechanism to derive instances for many commonly used classed, including Eq
.
show
function to do whatever you want to:instance Show a => Show (Err a) where
show (Value x) = show x
show (Error x) = "Error!" ++ show x
Note that the above definition required the types a
to already instantiate Show
. That is why the first line has an implication =>
.
Exercise: Make an Err a
an instance of the Eq
class, so that the following code is OK
Define two Err
values, z1
and z2
> z1 = Error "foo"
> z2 = Error "bar"
And then compare them in ghci:
z1 == z2
checkEq (Error 42) (Error 24)
> instance Eq a => Eq (Err a) where
> (Error x1) == (Error x2) = True
> (Value x1) == (Value x2) = x1 == x2
> (Error x1) == (Value x2) = False
> (Value x1) == (Error x2) = False