Presentation is loading. Please wait.

Presentation is loading. Please wait.

Haskell Chapter 5, Part II. Topics  Review/More Higher Order Functions  Lambda functions  Folds.

Similar presentations


Presentation on theme: "Haskell Chapter 5, Part II. Topics  Review/More Higher Order Functions  Lambda functions  Folds."— Presentation transcript:

1 Haskell Chapter 5, Part II

2 Topics  Review/More Higher Order Functions  Lambda functions  Folds

3 Higher Order Functions

4 Higher-Order functions applyTwice :: (a -> a) -> a -> a applyTwice f x = f (f x)  (a -> a) is a function  parentheses are needed.  a is (of course) a type parameter, maybe Int, String, etc.  BUT, parameter and result must have the same type  Try:  applyTwice(+3) 10  applyTwice (++ " woot") "say"  applyTwice (3:) [1]  Note that we are passing partially applied functions (e.g., 3:, +3, etc.)

5 Example: zipWith zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c] zipWith' _ [] _ = [] zipWith' _ _ [] = [] zipWith' f (x:xs) (y:ys) = f x y : zipWith' f xs ys  joins two lists by applying function to corresponding elements  must handle cases where lists are not equal length  lists don’t need to have same type  Try  zipWith' (+) [4,2,5] [2,6,2]  zipWith' (max) [4,2,5, 3] [2,6,2]  zipWith' (++) ["foo ", "bar "] ["fighters", "bells"]  zipWith' (*) (replicate 5 2) [1..] // replicates 2 5x  zipWith' (zipWith' (*)) [[2,3],[4,6]] [[10,20],[100, 200]]

6 Example: flip flip' :: (a->b->c) -> (b -> a -> c) flip' f = g where g x y = f y x  Try:  zip [1,2,3,4,5] "hello"  flip' zip [1,2,3,4,5] "hello"  zip "hello" [1,2,3,4,5]  let subIt x y = x - y  let subItFlipped = flip subIt  subIt 5 3  subItFlipped 5 3 Why would this be useful?

7 Lambda

8 Lambda -  Anonymous function we use when that function is only needed once  Typically use to pass to a higher-order function  Syntax:  \ (kind of like )  function parameters  ->  function body  Example: numLongChains :: Int numLongChains = length (filter (\xs -> length xs > 15) (map chain [1..100]))  compare to: numLongChains :: Int numLongChains = length (filter isLong (map chain [1..100])) where isLong xs = length xs > 15

9 When not to use lambda  Don’t use lambda when currying and partial application work… those are more readable  Example, use:  map (+3) [1,6,3,2]  Not  map (\x -> x + 3) [1,6,3,2]  Both work... but which would you rather read??

10 More on lambda functions  They can take multiple parameters zipWith (\a b -> (a * 30 + 3) / b) [5,4,3,2,1] [1,2,3,4,5]  Can include pattern matching  BUT, only one pattern (can’t fall through as in normal functions)  map (\(a, b) -> a + b) [(1,2),(3,4)]

11 Folds

12  A programming language can make it quicker to write code if it includes language constructs that capture common patterns  Think about common recursive pattern:  Base case: empty list  Pattern match x:xs  Perform some action on x and (recursively) on xs  In Haskell, this is what a fold does!  Can be used whenever you want to traverse a list once and return something.

13 More details  A fold takes:  A binary function (e.g., +, div, etc.)  A starting value (accumulator)  A list to fold up sum' :: (Num a) => [a] -> a sum' xs = foldl (\acc x -> acc + x) 0 xs  sum’ [2,4,5]  0 + 2  2 + 4  6 + 5  11 fold acc 0 [2,4,5] fold acc 2 [4,5] fold acc 6 [5][5] fold acc 11 []

14 Can use currying sum'' :: (Num a) => [a] -> a sum'' = foldl (+) 0  *Main> sum'' [3,5]  8  What happened to xs? The above returns a partially applied function that takes a list.  In general, if have fn foo a = bar b a  can rewrite as foo = bar b  then call foo a  Note that the definition is more concise without the lambda

15 Quick Exercise sum could be done as a fold at the command line, e.g.,  *Main> foldl (+) 0 [3,4,5]  12 EXERCISE  Use a fold1 to create the product of the numbers in a list (just do this at the GHCi prompt, no function definition)  Use a foldl to append strings stored in a list to an initial string of “Hello ”  Use a foldl to subtract a list of numbers from an initial value (could be subtracting purchases from your wallet, for example)

16 Right folds

17  foldr is like foldl, except it “eats up” the values starting from the right.  In some cases, the result is the same.  *Main> foldl (+) 0 [3,4,5]  12  *Main> foldr (+) 0 [3,4,5]  12 fold acc 0 [2,4,5] fold acc 5 [2, 4] fold acc 9 [2][2] fold acc 11 []

18 Right folds The accumulator value of a fold can be any type – including a list.  *Main> foldr (\x acc -> (^2) x:acc) [] [2,3,4]  [4,9,16]  Note that the order of the arguments is reversed from the order of the parameters  x acc parameters  [] [2,3,4] arguments  compare to left:  foldl (\acc x -> acc + x) 0 [2,3,4] fold acc [] [2,3, 4] fold acc [16] [2, 3] fold acc [9, 16] [2][2] fold acc [4,9,16] []

19 Right folds If arguments not reversed:  *Main> foldr (\x acc -> (^2) x:acc) [2,3,4] []  [2,3,4]  (nothing to “eat up” so result=acc) fold acc [2,3,4] [] [2, 3]

20 Can I trace this?  scanl and scanr (and scanl1, scanr1 ) are like foldl and foldr, except they report intermediate accumulator states.  Used to monitor the progress of a function that can be implemented as a fold.  *Main> foldl (+) 0 [3,5,2,1]  11  *Main> scanl (+) 0 [3,5,2,1]  [0,3,8,10,11]  *Main> scanr (\x acc -> (^2) x:acc) [] [2,3,4]  [[4,9,16],[9,16],[16],[]]  *Main> scanr (\x acc -> (^2) x:acc) [2,3,4] []  [[2,3,4]]

21 Right folds – to implement map  Like what we just did  foldr (\x acc -> (^2) x:acc) [] [2,3,4]  BUT use function passed as argument rather than ^2 map' :: (a -> b) -> [a] -> [b] map' f xs = foldr (\x acc -> f x : acc) [] xs  map' (+3) [1,2,3]  3 : [ ]  2 : [3]  1 : [2,3]  [1,2,3]

22 Which to use?  Could have done map with left fold: map'' :: (a -> b) -> [a] -> [b] map'' f xs = foldl (\acc x -> acc ++ [f x]) [] xs  Note that ++ is slower than :  (why would that make sense?)  SO, map' will be faster than map''

23 Another example – with Bool acc elem' :: (Eq a) => a -> [a] -> Bool elem' y ys = foldr (\x acc -> if x == y then True else acc) False ys  Note that accumulator starts with False  This code will work with an empty list elem' 'c' ['a'..'d'] Trace with your partner (we’ll do another one in a minute)

24 Two more folds  foldr1 and foldl1  Like foldr and foldl, but first (or last) element of the list is the starting value  Can’t be called with empty list  *Main> foldl1 (+) [2,3,4]  9  foldl max [4,6,2]  foldl 0 max [4,6,2]  foldl1 max [-4,-6,-2]  foldl 0 max [-4,-6,-2] – doesn’t work! needs type signature

25 foldl vs foldr  Try these:  foldr (subtract) 0 [5,4,3]  scanr (subtract) 0 [5,4,3]  scanr (subtract) [5,4,3] 0 -- doesn’t work, why?  foldl (subtract) 0 [5,4,3]  scanl (subtract) 0 [5,4,3]  foldl (flip (subtract)) 0 [5,4,3]  foldl1 (subtract) [5,4,3]  scanl1 (flip (subtract)) [5,4,3]

26 More fold examples reverse' :: [a] -> [a] reverse' = foldl (\acc x -> x : acc) []  OR reverse'' :: [a] -> [a] reverse'' = foldl (flip (:)) []  Quick exercise:  Trace reverse'' [1,2,3]  Remember: flip f x y = f y x  Hint: use scanl if you’re stuck on this

27 More fold examples filter' :: (a -> Bool) -> [a] -> [a] filter' p = foldr (\x acc -> if p x then x : acc else acc) [] last' :: [a] -> a last' = foldl1 (\_ x -> x)

28 Another look at folds  Can view as successive applications of some function to elements in a list  Assume right fold, binary function f, starting acc z  do foldr on [3,4,5,6]  this is essentially  f (f (f ( f z 6) 5) 4) 3  If f is + and starting value is 0, this is:  (((6 + 0) + 5) + 4) + 3 => 18  If f is subtract and starting value is 0, this is:  (((0 – 6) – 5) – 4) – 3 => -18  compare to foldl: 6 - (5 - (4 - (3 – 0))) => 2

29 Folds and infinite lists  && returns True if all elements are True, False if any element is False  So as soon as a False is encountered, the result is False and' :: [Bool] -> Bool and' xs = foldr (&&) True xs  and [True, False, True]  True && (False && (True && True))  Try: scanr (&&) True [True, False]

30 Using and with infinite list  repeat False  False && (False && (False && (False ….  Haskell is lazy. Only generates items as needed.  && returns False if one of its parameters is False. (&&) :: Bool -> Bool -> Bool True && x = x False && _ = False  *Main> and' (repeat False)  False  Foldr works with infinite lists IF binary function doesn’t always evaluate its second parameter (as in &&). Will not work with infinite lists if second parameter is always needed.

31 Play and Share – higher order functions  Write a function divisibleBy such that: divisibleBy 2 4 returns True, divisibleBy 2 5 returns False  Try: map (divisibleBy 2) [2,3,4]  Write a function divisibleByFive that returns a partially applied divisibleBy function  Try: map divisibleByFive [2,4,5]  Write isDivisibleByFive that uses a lambda function with map to achieve the same result (e.g., returns [False, False, True] for [2,4,5]) Suggested by a former student:  Create a higher-order function named integrate that takes a function, range, and step size and computes approximate numerical integration by evaluating the function at each step.  *Main> integrate square 2 4 0.001  18.66066700000209  *Main> integrate cube 2 4 0.001  59.97200299999252


Download ppt "Haskell Chapter 5, Part II. Topics  Review/More Higher Order Functions  Lambda functions  Folds."

Similar presentations


Ads by Google