Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or...
Transcript of Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or...
![Page 1: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/1.jpg)
Higher Order FunctionsChapter 11 of Thompson
http://learnyouahaskell.com/higher-order-functions
![Page 2: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/2.jpg)
A function that takes another function as input, or returns a function asoutput, is called a higher-order function.
Mastering higher order functions will make you a more productiveprogrammer.
Higher order functions
![Page 3: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/3.jpg)
A first example
We met the parametric polymorphic identity function:
id :: a -> aid x = x
Function types are just like any other type, so…
id :: (Int -> Char) -> (Int -> Char)
![Page 4: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/4.jpg)
Reminder about the associativity of ->
(Int -> Char) -> (Int -> Char)
Could be written as
(Int -> Char) -> Int -> Char
But not as Int -> Char -> (Int -> Char)or Int -> Char -> Int -> Char
![Page 5: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/5.jpg)
You have already seen many functions in this course with functions asoutput – any function with more than one ‘input’!
f :: Int -> (String -> Char)
• Two inputs (an Int and a String), returning a Char ✓• One input (an Int), returning a function of type String -> Char ✓
The second point of view is called partial application.
Functions as output
![Page 6: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/6.jpg)
multiply :: Int -> Int -> Intmultiply x y = x * y
![Page 7: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/7.jpg)
multiply :: Int -> Int -> Intmultiply x y = x * y
multiply 2 3
26
3
![Page 8: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/8.jpg)
multiply :: Int -> (Int -> Int)(multiply x) y = x * y
(multiply 2) 3
26
3
![Page 9: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/9.jpg)
multiply :: Int -> Int -> Intmultiply x y = x * y
multiply 2 is a function Int -> Int that doubles its input!
2
Partial application
![Page 10: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/10.jpg)
So just asmultiply :: Int -> Int -> Int
is convenient shorthand formultiply :: Int -> (Int -> Int)
We havemultiply 2 3
as convenient shorthand for(multiply 2) 3
![Page 11: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/11.jpg)
In general:
f e1 e2 … ekt1 -> t2 -> ... tn -> t
are shorthands for:
((...((f e1) e2)...) ek)t1 -> (t2 -> (...(tn -> t)...))
i.e., function application is left-associative-> is right-associative
![Page 12: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/12.jpg)
Functions as input
applyTwice:: (a -> a) -> a -> aapplyTwice f x = f (f x)
> applyTwice sqrt 162.0> applyTwice (+3) 1016
![Page 13: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/13.jpg)
Functions as input
applyTwice:: (a -> a) -> a -> aapplyTwice f x = f (f x)
> applyTwice (++ " HAHA") "HEY""HEY HAHA HAHA”> applyTwice ("HAHA " ++) "HEY""HAHA HAHA HEY"> applyTwice (3:) [1][3,3,1]
![Page 14: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/14.jpg)
Functions as input and output – Composition
Recall from the very first week that, given functionsf :: a -> b and g :: b -> c
We can define their composition, a functiong . f :: a -> c
So composition itself is a higher order function, with functions as both inputs and output.
![Page 15: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/15.jpg)
Composition
(.) :: (b -> c) -> (a -> b) -> (a -> c)(.) g f x = g (f x)
We usually write (.) g f infix as g . f
> ((+1) . (*2)) 13> ((*2) . (+1)) 14
![Page 16: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/16.jpg)
We have built-in functionseven :: Int -> Boolnot :: Bool -> Bool
Assume we want to definemyOdd :: Int -> BoolmyOdd x = not (even x)
more succinctly:
myOdd’ = not . even
![Page 17: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/17.jpg)
![Page 18: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/18.jpg)
![Page 19: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/19.jpg)
![Page 20: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/20.jpg)
Fold (also called “reduce”) functions
Often we wish to traverse a list once, element by element, building up an output as we go.
This is called a fold.
There are ‘right folds’ and ‘left folds’; we will try to understand right folds before we look at the left.
These are the most useful higher order function and are worth understanding – they will make you a more productive programmer!
![Page 21: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/21.jpg)
Folds
Often we wish to traverse a list once, element by element, building up an output as we go.
• Add each number in a list to get the sum of all the elements;• Multiply each number in a list to get the product of all the elements;• Increment a number by 1 for each element to get the list’s length;• Turn a list of strings into an acronym;• Map a function over a list element by element;• etc…
![Page 22: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/22.jpg)
mySum :: [Int] -> IntmySum list = case list of[] -> 0x:xs -> x + mySum xs
myLen :: [a] -> IntmyLen list = case list of[] -> 0x:xs -> 1 + myLen xs
myProd :: [Int] -> IntmyProd list = case list of[] -> 1x:xs -> x * myProd xs
acro :: [String] -> Stringacro list = case list of[] -> ""x:xs -> head x : acro xs
How are these definitions different? How are they the same?
![Page 23: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/23.jpg)
mySum :: [Int] -> IntmySum list = case list of[] -> 0x:xs -> x + mySum xs
myLen :: [a] -> IntmyLen list = case list of[] -> 0x:xs -> 1 + myLen xs
myProd :: [Int] -> IntmyProd list = case list of[] -> 1x:xs -> x * myProd xs
acro :: [String] -> Stringacro list = case list of[] -> ""x:xs -> head x : acro xs
The names are different – but Haskell doesn’t really care about that
![Page 24: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/24.jpg)
mySum :: [Int] -> IntmySum list = case list of[] -> 0x:xs -> x + mySum xs
myLen :: [a] -> IntmyLen list = case list of[] -> 0x:xs -> 1 + myLen xs
myProd :: [Int] -> IntmyProd list = case list of[] -> 1x:xs -> x * myProd xs
acro :: [String] -> Stringacro list = case list of[] -> ""x:xs -> head x : acro xs
The types are different – suggests folds are polymorphic
![Page 25: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/25.jpg)
mySum :: [Int] -> IntmySum list = case list of[] -> 0x:xs -> x + mySum xs
myLen :: [a] -> IntmyLen list = case list of[] -> 0x:xs -> 1 + myLen xs
myProd :: [Int] -> IntmyProd list = case list of[] -> 1x:xs -> x * myProd xs
acro :: [String] -> Stringacro list = case list of[] -> ""x:xs -> head x : acro xs
The base cases are different
![Page 26: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/26.jpg)
mySum :: [Int] -> IntmySum list = case list of[] -> 0x:xs -> x + mySum xs
myLen :: [a] -> IntmyLen list = case list of[] -> 0x:xs -> 1 + myLen xs
myProd :: [Int] -> IntmyProd list = case list of[] -> 1x:xs -> x * myProd xs
acro :: [String] -> Stringacro list = case list of[] -> ""x:xs -> head x : acro xs
The step cases are different – but only a little! – different recipes to combine the head with the recursive call on the tail
![Page 27: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/27.jpg)
mySum :: [Int] -> IntmySum list = case list of[] -> 0x:xs -> x + mySum xs
myLen :: [a] -> IntmyLen list = case list of[] -> 0x:xs -> 1 + myLen xs
myProd :: [Int] -> IntmyProd list = case list of[] -> 1x:xs -> x * myProd xs
acro :: [String] -> Stringacro list = case list of[] -> ""x:xs -> head x : acro xs
Everything else is the same!
![Page 28: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/28.jpg)
Fold Right
This suggests that we could define a polymorphic higher order function that takes as input• a base case;• a recipe for combining the head with a recursive call on the tailand then does all of the rest of the work for us!
No more time-consuming error-prone recursions to write• Except for all the ones that don’t follow the format of the previous slide
![Page 29: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/29.jpg)
![Page 30: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/30.jpg)
foldr
![Page 31: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/31.jpg)
foldr in action
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr :: (Int -> Int -> Int) -> Int -> [Int] -> Int
mySum = foldr (+) 0
myProd = foldr (*) 1
![Page 32: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/32.jpg)
foldr in action
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr :: (a -> Int -> Int) -> Int -> [a] -> Int
myLen = foldr (\x y -> y + 1) 0
Or, to avoid a warning:
myLen = foldr (\_ y -> y + 1) 0
![Page 33: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/33.jpg)
foldr in action
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr :: (String -> String -> String) -> String -> [String] -> String
acro = foldr (\x y -> head x : y) ""
How might you write a ‘safe’ version of acro that ignores empty strings instead of crashing on them?
![Page 34: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/34.jpg)
foldr in action
foldr is just another function, and can be used as a helper anywhere:
myMaximum :: [Int] -> IntmyMaximum list = case list of[] -> error "No maximum of an empty list"x:xs -> foldr max x xs
Take some time to understand all the types here!
![Page 35: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/35.jpg)
Defining foldr
myFoldr :: (a -> b -> b) -> b -> [a] -> bmyFoldr combine base list = case list of[] -> basex:xs -> combine x (myFoldr combine base xs)
![Page 36: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/36.jpg)
Why is it fold right?
foldr (+) 0 [1,2,3]= 1 + foldr (+) 0 [2,3]= 1 + (2 + foldr (+) 0 [3])= 1 + (2 + (3 + foldr (+) 0 []))= 1 + (2 + (3 + 0))
So the combining operation associates to the right.• i.e. start with the base case, combine it with the rightmost element of list,
then continue until we reach the leftmost element of the list.
![Page 37: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/37.jpg)
foldr and the structure of lists
A list [1,2,3]is really 1 : (2 : (3 : []) )
foldr replaces [] with a base case and : with a combining function
e.g. 1 + (2 + (3 + 0) )
So folding right is very natural because lists themselves associate right
![Page 38: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/38.jpg)
![Page 39: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/39.jpg)
Left folds
mySuml :: [Int] -> IntmySuml = mySumAcc 0wheremySumAcc acc list = case list of[] -> accx:xs -> mySumAcc (acc + x) xs
In the above, mySumAcc has type Int -> [Int] -> Int
![Page 40: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/40.jpg)
Left folds
mySuml [1,2,3]= mySumAcc 0 [1,2,3]= mySumAcc (0 + 1) [2,3]= mySumAcc ((0 + 1) + 2) [3]= mySumAcc (((0 + 1) + 2) + 3) []= (((0 + 1) + 2) + 3)
No difference for +, but not all combining operations are associative!
![Page 41: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/41.jpg)
![Page 42: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/42.jpg)
It folds the list up from the left side
![Page 43: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/43.jpg)
Defining foldl
myFoldl :: (b -> a -> b) -> b -> [a] -> bmyFoldl combine acc list = case list of[] -> accx:xs -> myFoldl combine (combine acc x) xs
Compare to the final line of the right fold:
x:xs -> combine x (myFoldr combine base xs)
![Page 44: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/44.jpg)
foldl, folding left
foldl (+) 0 [1,2,3]= foldl (+) (0 + 1) [2,3]= foldl (+) ((0 + 1) + 2) [3]= foldl (+) (((0 + 1) + 2) + 3) []= (((0 + 1) + 2) + 3)
So the combining operation associates to the left.• i.e. start with the accumulator, combine it with the leftmost element of list,
then continue until we reach the empty list and return the accumulator.
![Page 45: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/45.jpg)
foldr versus foldl
An example where they give different answers:
> foldr (-) 0 [1,2,3]2
> foldl (-) 0 [1,2,3]-6
Because ((0 – 1) – 2) – 3 ≠ 1 – (2 – (3 – 0))
![Page 46: Higher Order Functions · 2019. 7. 18. · A function that takes another function as input, or returns a function as output, is called a higher-order function. Mastering higher order](https://reader033.fdocuments.in/reader033/viewer/2022051900/5fef52ffcdab0345ef761b2f/html5/thumbnails/46.jpg)
foldr versus foldl
More generally, if we think of lists as built up from the empty list by using cons repeatedly, then lists are constructed from the right.
Therefore foldr tends to follow the way lists are constructed.
e.g. foldr (:) [] :: [a] -> [a] is the identity!
foldl goes in the reverse direction from the list’s construction• What happens if you use (:) with foldl?