90 likes | 233 Views
Functional Programming Lecture 9 - type overloading and type classes. Type Polymorphism. A function is polymorphic if it has many types. E.g. length :: [Char] -> Int length :: [Int] -> Int length :: [[Int]] -> Int
E N D
Functional ProgrammingLecture 9 - type overloading and type classes
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 typevariable: length :: [a] -> Int
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
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.
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.
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
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! 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!
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