Transcript Lecture 9
Functional Programming
Lecture 9 type overloading and
type classes
1
Type Polymorphism
A function is polymorphic if it has many types.
E.g.
length :: [Char] -> Int
length :: [Int] -> Int
length :: [[Int]] -> Int
Polymorphism is only appropriate when the function
has a single definition (e.g. length x:xs = 1 + length xs,
etc.) which works over all types.
To define a polymorphic function, we use a type
variable:
length :: [a] -> Int
2
Type Overloading
Type overloading is used when a function has a variety
of types and different definitions are used for different
types.
E.g. check whether an element is a member of a list.
elemBool :: Bool -> [Bool] -> Bool
elemBool x [] = False
elemBools x (y:ys) = (x ==Bool y) || elemBool x ys
elemInt :: Int -> [Int] -> Bool
would differ only in its use of ==Int instead of ==Bool .
Clearly these equalities are different, e.g.
True ==Bool False = False
True ==Bool True = True
...
0 ==Int 0 = True
(m+1) ==Int (n+1) = m ==Int n
3
Type Overloading
One solution:
make the equality function a parameter of the general
function
elemGen :: (a -> a -> Bool) -> a -> [a] -> Bool
Alternative solution:
define a function which uses the overloaded equality
elem :: a -> [a] -> Bool
But restricts a to types which have an equality.
This is more
- readable
- amenable to reuse.
Type classes are the mechanism which allow us to
define functions like elem with type requirements.
4
Type Classes
The Equality class
class Eq a where
(==) :: a -> a -> Bool
Many built-in types are instances of Eq:
Float, Int, Bool, Char, tuples and lists. E.g. if a is Int
then == is ==Int.
To use a type class, we insert a context into a type.
E.g.
elem :: (Eq a) => a -> [a] -> Bool
(Eq a) => is called the context. It expresses a
requirement of the type a, namely, it must have an
equality operator.
5
Examples
Check 3 values are equal.
allEqual :: Eq a => a -> a -> a -> Bool
allEqual x y z = (x == y) && (y == z)
So,
• we can check Integers:
allEqual 1 2 3 which returns False, because
Int is an Eq type and therefore
allEqual :: Int -> Int -> Int -> Bool
• we can check pairs of Integers and Characters:
allEqual (1,’a’) (1,’a’) (1’a’) which returns True,
because
tuples of Int and Char is an Eq type (because both Int
and Char are Eq types) and therefore
allEqual :: (Int,Char) -> (Int ,Char) ->(Int ,Char) ->
Bool
6
But, we cannot compare functions from Int to Int with
allEqual
Assume
succ :: Int -> Int
succ x = x+1
What happens when we evaluate
allEqual succ succ succ ?
We get a type error:
ERROR: Int -> Int is not an instance of class “Eq”
because (Int -> Int) is not a member of the class Eq,
in other words, we have not defined == on functions!
Make sure you understand this -- it is quite likely that
you will see this kind of error often!
7
Note: type of allEqual (succ x) (succ x) (succ x)?
More type classes
You can define your own type classes (unlikely in this
course), and use further built-in ones (more likely!).
3 most common classes:
Eq
class Eq a where
(==), (/=) :: a-> a -> Bool
x /= y = not (x == y)
x == y = not (x/= y)
Ord
class (Eq a)=> Ord a where
<, >, <=, >= :: a -> a -> Bool
max, min :: a -> a -> a
max x y
| x >= y = x
| otherwise = y
etc.
Class Ord includes class Eq!
8
Show
class Show a where
show :: a -> String
most types belong to this class, even functions which
are displayed as <<function>>.
Reminder: a type context uses the symbol =>
a type uses the symbol ->
E.g. elem :: Eq a => a -> [a] -> Bool
9