
Higher-Order Functions A function is Higher-Order if it takes a function as an CSc 520 argument or returns one as its result. Higher-order function aren’t weird; the differentiation Principles of Programming operation from high-school calculus is higher-order: Languages deriv :: (Float->Float)->Float->Float 16: Haskell — Higher-Order Functions deriv f x = (f(x+dx) - f x)/0.0001 Christian Collberg Many recursive functions share a similar structure. We [email protected] can capture such “recursive patterns” in a higher-order function. Department of Computer Science University of Arizona We can often avoid the use of explicit recursion by using higher-order functions. This leads to functions Copyright c 2004 Christian Collberg that are shorter, and easier to read and maintain. 520—Spring 2005—16 [1] 520—Spring 2005—16 [2] Currying Revisited Currying Revisited. We have already seen a number of higher-order How is a curried function defined? functions. In fact, any curried function is higher-order. A curried function of n arguments (of types Why? Well, when a curried function is applied to one of t1; t2; · · · ; tn) that returns a value of type t is defined its arguments it returns a new function as the result. like this: Uh, what was this currying thing? fun :: t1 -> t2 -> · · · -> tn -> t A curried function does not have to be applied to all its This is sort of like defining n different functions (one for arguments at once. We can supply some of the each ->). In fact, we could define these functions arguments, thereby creating a new specialized function. explicitly, but that would be tedious: This function can, for example, be passed as argument to a higher-order function. fun1 :: t2 -> · · · -> tn -> t fun1 a2 · · · an = · · · fun2 :: t3 -> · · · -> tn -> t fun2 a3 · · · an = · · · 520—Spring 2005—16 [3] 520—Spring 2005—16 [4] Currying Revisited. Currying Revisited. Duh, how about an example? get fifth "Bartholomew" ) 'h' Certainly. Lets define a recursive function get nth n xs which returns the n:th element from the list xs: map (get nth 3) ["mob","sea","tar","bat"] ) get nth 1 (x: ) = x "bart" get nth n ( :xs) = get nth (n-1) xs So, what’s the type of get second? get nth 10 "Bartholomew" ) 'e' Remember the Rule of Cancellation? The type of get nth is Int -> [a] -> a. Now, let’s use get nth to define functions get second, get third, get fourth, and get second applies get nth to one argument. So, to get fifth, without using explicit recursion: get the type of get second we need to cancel get nth’s first type: Intnnn -> [a] -> a ≡ [a] -> a. get second = get nth 2 get fourth = get nth 4 get third = get nth 3 get fifth = get nth 5 520—Spring 2005—16 [5] 520—Spring 2005—16 [6] Patterns of Computation The map Function Mappings map takes two arguments, a function and a list. map Apply a function f to the elements of a list L to make a creates a new list by applying the function to each new list L0. Example: Double the elements of an integer element of the input list. list. map’s first argument is a function of type a -> b. The second argument is a list of type [a]. The result is a list Selections of type [b]. Extract those elements from a list L that satisfy a 0 map :: (a -> b) -> [a] -> [b] predicate p into a new list L . Example: Extract the even map f [ ] = [ ] elements from an integer list. map f (x:xs) = f x : map f xs Folds We can check the type of an object using the :type Combine the elements of a list L into a single element command. Example: :type map. using a binary function f. Example: Sum up the elements in an integer list. 520—Spring 2005—16 [7] 520—Spring 2005—16 [8] The map Function. The map Function. map :: (a -> b) -> [a] -> [b] map :: (a -> b) -> [a] -> [b] map f [ ] = [ ] map f [ ] = [ ] map f (x:xs)= f x : map f xs inc [1,2,3,4] map f (x:xs) = f x : map f xs inc x = x + 1 map f [ ] = [ ] means: “The result of applying the function f to map the elements of an empty list is the empty list.” map inc [1,2,3,4] ) [2,3,4,5] map f (x:xs) = f x : map f xs means: “applying f to the list [inc 1,inc 2,inc 3,inc 4] (x:xs) is the same as applying f to x (the first element of the list), then applying f to the list xs, and then combining the results.” [2,3,4,5] 520—Spring 2005—16 [9] 520—Spring 2005—16 [10] The map Function. The filter Function Simulation: Filter takes a predicate p and a list L as arguments. It map square [5,6] ) returns a list L0 consisting of those elements from L that square 5 : map square [6] ) satisfy p. 25 : map square [6] ) The predicate p should have the type a -> Bool, 25 : (square 6 : map square [ ]) ) where a is the type of the list elements. 25 : (36 : map square [ ]) ) 25 : (36 : [ ]) ) Examples: 25 : [36] ) filter even [1..10] [2,4,6,8,10] [25,36] ) filter even (map square [2..5]) ) filter even [4,9,16,25] ) [4,16] filter gt10 [2,5,9,11,23,114] where gt10 x = x > 10 ) [11,23,114] 520—Spring 2005—16 [11] 520—Spring 2005—16 [12] The filter Function. The filter Function. We can define filter using either recursion or list filter :: (a->Bool)->[a]->[a] comprehension. filter [] = [] filter p (x:xs) even [1,2,3,4] Using recursion: | p x = x : filter p xs filter :: (a -> Bool) -> [a] -> [a] | otherwise = filter p xs f filter [] = [] [even 1, even 2, i even 3, even 4] l filter p (x:xs) filter even [1,2,3,4] ) [2,4] t [False, True, e | p x = x : filter p xs False, True] | otherwise = filter p xs r Using list comprehension: filter :: (a -> Bool) -> [a] -> [a] [2,4] filter p xs = [x | x <- xs, p x] 520—Spring 2005—16 [13] 520—Spring 2005—16 [14] The filter Function. fold Functions doublePos doubles the positive integers in a list. A common operation is to combine the elements of a list into one element. Such operations are called getEven :: [Int] -> [Int] reductions or accumulations. getEven xs = filter even xs Examples: doublePos :: [Int] -> [Int] sum [1,2,3,4,5] ≡ doublePos xs = map dbl (filter pos xs) (1 + (2 + (3 + (4 + (5 + 0))))) ) 15 where dbl x = 2 * x concat ["H","i","!"] ≡ pos x = x > 0 ("H" ++ ("i" ++ ("!" ++ ""))) ) "Hi!" Simulations: getEven [1,2,3] ) [2] Notice how similar these operations are. They both combine the elements in a list using some binary doublePos [1,2,3,4] ) operator (+, ++), starting out with a “seed” value (0, map dbl (filter pos [1,2,3,4]) ) ""). map dbl [2,4] ) [4,8] 520—Spring 2005—16 [15] 520—Spring 2005—16 [16] fold Functions. fold Functions. Haskell provides a function foldr (“fold right”) which Note how the fold process is started by combining the captures this pattern of computation. last element xn with z. Hence the name seed. foldr takes three arguments: a function, a seed value, foldr z x xn x x xn z and a list. (⊕) [ 1 · · · ] = ( 1 ⊕ ( 2 ⊕ (· · · ( ⊕ )))) Examples: Several functions in the standard prelude are defined foldr (+) 0 [1,2,3,4,5] ) 15 using foldr: foldr (++) "" ["H","i","!"] ) "Hi!" and,or :: [Bool] -> Bool foldr: and xs = foldr (&&) True xs foldr :: (a->b->b) -> b -> [a] -> b or xs = foldr (||) False xs foldr f z [ ] = z ? or [True,False,False] ) foldr f z (x:xs) = f x (foldr f z xs) foldr (||) False [True,False,False] ) True || (False || (False || False)) ) True 520—Spring 2005—16 [17] 520—Spring 2005—16 [18] fold Functions. fold Functions. Remember that foldr binds from the right: In the case of (+) and many other functions foldr (+) 0 [1,2,3] ) (1+(2+(3+0))) foldl(⊕)z[x1 · · · xn] = foldr(⊕)z[x1 · · · xn] There is another function foldl that binds from the left: However, one version may be more efficient than the foldl (+) 0 [1,2,3] ) (((0+1)+2)+3) other. In general: foldl(⊕)z[x1 · · · xn] = (((z ⊕ x1) ⊕ x2) ⊕ · · · ⊕ xn) 520—Spring 2005—16 [19] 520—Spring 2005—16 [20] fold Functions. Operator Sections ⊕ ⊕ We’ve already seen that it is possible to use operators to construct new functions: ⊕ x1 ⊕ xn x2 ⊕ (*2) – function that doubles its argument ⊕ x3 x3 (>2) – function that returns True for numbers > 2. ⊕ ⊕ x2 xn z z x1 Such partially applied operators are know as operator foldr ⊕ z [x1 · · · xn] foldl ⊕ z [x1 · · · xn] sections. There are two kinds: (op a) b = b op a (*2) 4 = 4 * 2 = 8 (>2) 4 = 4 > 2 = True (++ "nn") "Bart" = "Bart" ++ "nn" 520—Spring 2005—16 [21] 520—Spring 2005—16 [22] Operator Sections. takeWhile & dropWhile (a op) b = a op b We’ve looked at the list-breaking functions drop & (3:) [1,2] = 3 : [1,2]= [3,1,2] take: (0<) 5 = 0 < 5 = True (1/) = 1/5 take 2 ['a','b','c'] ) ['a','b'] Examples: drop 2 ['a','b','c'] ) ['c'] (+1) – The successor function. takeWhile and dropWhile are higher-order list-breaking functions. They take/drop elements from a (/2) – The halving function. list while a predicate is true. (:[]) – The function that turns an element into a singleton list. takeWhile even [2,4,6,5,7,4,1] ) [2,4,6] More Examples: dropWhile even [2,4,6,5,7,4,1] ) ? filter (0<) (map (+1) [-2,-1,0,1]) [5,7,4,1] [-1] 520—Spring 2005—16 [23] 520—Spring 2005—16 [24] takeWhile & dropWhile.
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages8 Page
-
File Size-