200 likes | 321 Views
Polymorphism and Overloading. Prelude> [1,2,3] ++ [4,5,6]. [1,2,3,4,5,6] :: [Integer] Prelude> ['a','b','c'] ++ ['d','e','f'] "abcdef" :: [Char] Prelude> "abc" ++ "def" "abcdef" :: [Char] Prelude> ["abc","def","ghi"] ++ ["uvw","xyz"] ["abc","def","ghi","uvw","xyz"] :: [[Char]]
E N D
Polymorphism and Overloading Lecture 9 Polymorphism, Overloading and Higher Order Functions
Prelude> [1,2,3] ++ [4,5,6] [1,2,3,4,5,6] :: [Integer] Prelude> ['a','b','c']++['d','e','f'] "abcdef" :: [Char] Prelude> "abc"++"def" "abcdef" :: [Char] Prelude> ["abc","def","ghi"]++["uvw","xyz"] ["abc","def","ghi","uvw","xyz"] :: [[Char]] What is the type of ++ : [a] -> [a] -> [a] Lecture 9 Polymorphism, Overloading and Higher Order Functions
lengthList [] = 0 lengthList (x:xs) = 1 + lengthList xs Main> lengthList ['a','b','c'] 3 :: Integer Main> lengthList [1,2,3,4,5,6] 6 :: Integer Main> lengthList [['a','b','c'],['d','e','f'],['g'],['h','i']] 4 :: Integer Main> lengthList ["abc","def"] 2 :: Integer What is the type of lengthList? [a] ->Int Lecture 9 Polymorphism, Overloading and Higher Order Functions
Polymorphism: “has many shapes”. A function is polymorphic if it can operate on many different types. In polymorphism, the same function definition is used for all the types it is applied to. In polymorphism type variables are used, as in: [a]->[a]->[a] [a] ->Int (a,b) ->[a] The variable a stands for an arbitrary type. Of course all the a’s in the first declaration above stand for the same type wheras in the third, a and b can be different types. Lecture 9 Polymorphism, Overloading and Higher Order Functions
Overloading is another mechanism for using the same function name on different types. An overloaded function has different definitions for different types. ‘a’ = = ‘b’ (a,b) = = (c,d) would require different definitions of “= =“. (a = = c) && (b = = d) Lecture 9 Polymorphism, Overloading and Higher Order Functions
Higher Order Functions Lecture 9 Polymorphism, Overloading and Higher Order Functions
A higher order function takes a function as an argument or returns a function as a result. When we apply a function to all elements of a list, we say that we have mapped that function into the list. There is a Haskell built-in function called map that is used for this purpose. map f list = [ f x | x <- list] map f [ ] = [ ] map f (first:rest) = f first : map f rest Prelude> map odd[1,2,3,4,5] [True,False,True,False,True] Prelude> map (^2) [1,2,3] [1,4,9] Fact> map fact [3,4,5] [6,24,120] map: apply to all Lecture 9 Polymorphism, Overloading and Higher Order Functions
Elements of the list to which the function is applied Elements of the output list that the function returns Type of map: input function input list output list map :: ( a -> b) -> [a] -> [b] Lecture 9 Polymorphism, Overloading and Higher Order Functions
A function which doubles all the values in a listof integers: double :: Int -> Int double n = n*2 doubleAll :: [Int] -> [Int] doubleAll [] = [] doubleAll (first:rest) = (double first) : (doubleAll rest) A function that squares all the values in a list of integers: square :: Int -> Int square n = n^2 squareAll :: [Int] -> [Int] squareAll [] = [] squareAll (first : rest) = (square first) : (squareAll rest) Lecture 9 Polymorphism, Overloading and Higher Order Functions
A function thatreturns a list of factorials of all the numbers in a given list of integers: fact :: Int -> Int fact n = product [1..n] factAll :: [Int] -> [Int] factAll [] = [] factAll (first : rest) = (factfirst) : (factAllrest) There is a pattern that is repeated in all these definitions. Here is where we can use a higher order function. We may write a general function: doAll :: (Int -> Int) -> [Int] -> [Int] doAllf [] = [] doAllf (first : rest) = (f first ) : (doAll f rest) All we need is this one general definition and the definitions of each of the functions to be applied to each element. Lecture 9 Polymorphism, Overloading and Higher Order Functions
double :: Int -> Int double n = n*2 square :: Int -> Int square n = n^2 fact :: Int -> Int fact n = product [1..n] doAll :: (Int -> Int) -> [Int] -> [Int] doAllf [] = [] doAllf (first : rest) = (f first ) : (doAll f rest) Main> doAll double [1,2,3,4] [2,4,6,8] Main> doAll fact [1,2,3,4] [1,2,6,24] Main> doAll square [1,2,3,4] [1,4,9,16] Lecture 9 Polymorphism, Overloading and Higher Order Functions
Alternatively, we could define all the functions in one line each using our higher order function doAll: doubleAll2 :: [Int] -> [Int ] doubleAll2 list = doAlldouble list squareAll2 :: [Int] -> [Int ] squareAll2 list = doAllsquarelist factAll2 :: [Int] -> [Int ] factAll2 list = doAllfactlist Main> factAll2[1,2,3,4] [1,2,6,24] Main> doubleAll2 [1,2,3,4] [2,4,6,8] Main> doAll square [1,2,3,4] [1,4,9,16] Lecture 9 Polymorphism, Overloading and Higher Order Functions
We could even have used the built-in function map: doubleAll = map double where double x = 2*x Main> doAll double [1,2,3,4] [2,4,6,8] Main> map double [1,2,3,4] [2,4,6,8] Main> doAll fact [1,2,3,4] [1,2,6,24] Main> map fact [1,2,3,4] [1,2,6,24] Main> doAll square [1,2,3,4] [1,4,9,16] :: [Int] Main> map square [1,2,3,4] [1,4,9,16] Main> doubleAll [1,2,3] [2,4,6] Lecture 9 Polymorphism, Overloading and Higher Order Functions
We can think of map as a function which takes a function of type Int -> Int and returns a function of type [Int] -> [Int] or: map:: (Int -> Int) -> ([Int] -> [Int]) -- “->”is right associative So, we can define the following functions which return a function as their result: doubleAll3 :: [Int] -> [Int ] doubleAll3 = map double squareAll3 :: [Int] -> [Int] squareAll3 = map square factAll3 :: [Int] -> [Int] factAll3 = map fact Main> squareAll3 [1,2,3,4,5] [1,4,9,16,25] :: [Int] Lecture 9 Polymorphism, Overloading and Higher Order Functions
Filtering Function remove (removes an element from a list): remove _ [] = [] remove element (first : rest) = if element == first then remove element rest else first :(remove element rest) We may want to write a function that removes all even or odd elements or elements that satisfy a certain condition. Main> removeOdd [1,2,3,4,5,6] [2,4,6] removeOdd [ ] = [ ] removeOdd (first:rest) = if odd first then removeOdd rest else first:removeOdd rest Lecture 9 Polymorphism, Overloading and Higher Order Functions
Main> removeEven [1,2,3,4,5,6] [1,3,5] removeEven []=[] removeEven (first:rest)= if even first then removeEven rest else first:removeEven rest We can write a general function that does all of these. removeAll p [ ] = [ ] removeAll p (first : rest) = if p first then removeAll p rest else first : removeAll p rest Lecture 9 Polymorphism, Overloading and Higher Order Functions
Main> removeAll odd[1,2,3,4,5,6] [2,4,6] Main> removeAll even [1,2,3,4,5,6] [1,3,5] We could have used filter to do all this rather than defining removeAll. This is another useful built-in function. It takes a property and a list and returns a list containing the elements that have that property. Main> filter odd [1,2,3,4,5,6] [1,3,5] Main> filter even [1,2,3,4,5,6,7] [2,4,6] Lecture 9 Polymorphism, Overloading and Higher Order Functions
The property is a function that returns a Bool Elements of the input list, the output list that the function returns and the type that the property works on Type of filter: input function input list output list filter :: ( a -> Bool) -> [a] -> [a] Lecture 9 Polymorphism, Overloading and Higher Order Functions
Definition of filter Fortunately, filter is a built-in function. If it wasn’t a built-in function, we could have defined filter as follows. filter :: (Int -> Bool) -> [Int] -> [Int] filter p [] = [] filter p (first : rest) = if (p first) then first : (filter p rest) else filter p rest Lecture 9 Polymorphism, Overloading and Higher Order Functions