0% found this document useful (0 votes)
5 views

Slides-11-haskell

Higher-order functions are functions that take other functions as arguments or return them as results, allowing for more concise and readable code. The document discusses concepts such as currying, mapping, filtering, and folding, providing examples of how these functions operate on lists. It also introduces operator sections and higher-order list-breaking functions like takeWhile and dropWhile.

Uploaded by

rauniyaraman66
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views

Slides-11-haskell

Higher-order functions are functions that take other functions as arguments or return them as results, allowing for more concise and readable code. The document discusses concepts such as currying, mapping, filtering, and folding, providing examples of how these functions operate on lists. It also introduces operator sections and higher-order list-breaking functions like takeWhile and dropWhile.

Uploaded by

rauniyaraman66
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 31

Higher-Order Functions

A function is Higher-Order if it takes a function as an


argument or returns one as its result.
Higher-order function aren’t weird; the differentiation
operation from high-school calculus is higher-order:

deriv :: (Float->Float)->Float->Float
deriv f x = (f(x+dx) - f x)/0.0001

Many recursive functions share a similar structure. We can


capture such “recursive patterns” in a higher-order function.
We can often avoid the use of explicit recursion by using
higher-order functions. This leads to functions that are
shorter, and easier to read and maintain.

2/32
Currying Revisited

We have already seen a number of higher-order functions. In


fact, any curried function is higher-order. Why? Well, when a
curried function is applied to one of its arguments it returns a
new function as the result.
Uh, what was this currying thing?
A curried function does not have to be applied to all its
arguments at once. We can supply some of the arguments,
thereby creating a new specialized function. This function
can, for example, be passed as argument to a higher-order
function.

3/32
Currying Revisited. . .

How is a curried function defined?


A curried function of n arguments (of types t1 , t2 , · · · , tn )
that returns a value of type t is defined like this:

fun :: t1 -> t2 -> · · · -> tn -> t

This is sort of like defining n different functions (one for each


->). In fact, we could define these functions explicitly, but
that would be tedious:

fun1 :: t2 -> · · · -> tn -> t


fun1 a2 · · · an = · · ·

fun2 :: t3 -> · · · -> tn -> t


fun2 a3 · · · an = · · ·

4/32
Currying Revisited. . .

Duh, how about an example?


Certainly. Lets define a recursive function get nth n xs
which returns the n:th element from the list xs:

get nth 1 (x: ) = x


get nth n ( :xs) = get nth (n-1) xs

get nth 10 "Bartholomew" ⇒ ’e’

Now, let’s use get nth to define functions get second,


get third, get fourth, and get fifth, without using
explicit recursion:
get second = get nth 2 get fourth = get nth 4
get third = get nth 3 get fifth = get nth 5

5/32
Currying Revisited. . .

get fifth "Bartholomew" ⇒ ’h’

map (get nth 3)


["mob","sea","tar","bat"] ⇒
"bart"

So, what’s the type of get second?


Remember the Rule of Cancellation?
The type of get nth is Int -> [a] -> a.
get second applies get nth to one argument. So, to get the
type of get second we need to cancel get nth’s first type:
\\\ -> [a] -> a ≡ [a] -> a.
Int

6/32
Patterns of Computation

Mappings
Apply a function f to the elements of a list L to make a new
list L′ . Example: Double the elements of an integer list.
Selections
Extract those elements from a list L that satisfy a predicate p
into a new list L′ . Example: Extract the even elements from
an integer list.
Folds
Combine the elements of a list L into a single element using a
binary function f . Example: Sum up the elements in an
integer list.

7/32
The map Function

map takes two arguments, a function and a list. map creates a


new list by applying the function to each element of the input
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 of type [b].

map :: (a -> b) -> [a] -> [b]


map f [ ] = [ ]
map f (x:xs) = f x : map f xs

We can check the type of an object using the :type


command. Example: :type map.

8/32
The map Function. . .

map :: (a -> b) -> [a] -> [b]


map f [ ] = [ ]
inc [1,2,3,4]
map f (x:xs)= f x : map f xs

inc x = x + 1
map

map inc [1,2,3,4] ⇒ [2,3,4,5]


[inc 1,inc 2,inc 3,inc 4]

[2,3,4,5]

9/32
The map Function. . .

map :: (a -> b) -> [a] -> [b]


map f [ ] = [ ]
map f (x:xs) = f x : map f xs

map f [ ] = [ ] means: “The result of applying the function f to


the elements of an empty list is the empty list.”
map f (x:xs) = f x : map f xs means: “applying f to the list
(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.”

10/32
The map Function. . .

Simulation:

map square [5,6] ⇒


square 5 : map square [6] ⇒
25 : map square [6] ⇒
25 : (square 6 : map square [ ]) ⇒
25 : (36 : map square [ ]) ⇒
25 : (36 : [ ]) ⇒
25 : [36] ⇒
[25,36]

11/32
The filter Function

Filter takes a predicate p and a list L as arguments. It returns


a list L′ consisting of those elements from L that satisfy p.
The predicate p should have the type a -> Bool, where a is
the type of the list elements.
Examples:

filter even [1..10] ⇒ [2,4,6,8,10]


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]

12/32
The filter Function. . .

We can define filter using either recursion or list


comprehension.
Using recursion:

filter :: (a -> Bool) -> [a] -> [a]


filter [] = []
filter p (x:xs)
| p x = x : filter p xs
| otherwise = filter p xs

Using list comprehension:

filter :: (a -> Bool) -> [a] -> [a]


filter p xs = [x | x <- xs, p x]

13/32
The filter Function. . .

filter :: (a->Bool)->[a]->[a]
filter [] = []
even [1,2,3,4]
filter p (x:xs)
| p x = x : filter p xs
| otherwise = filter p xs f
[even 1, even 2,
i
even 3, even 4]
l
filter even [1,2,3,4] ⇒ [2,4] t
[False, True,
e
False, True] r

[2,4]

14/32
The filter Function. . .

doublePos doubles the positive integers in a list.


getEven :: [Int] -> [Int]
getEven xs = filter even xs

doublePos :: [Int] -> [Int]


doublePos xs = map dbl (filter pos xs)
where dbl x = 2 * x
pos x = x > 0
Simulations:
getEven [1,2,3] ⇒ [2]

doublePos [1,2,3,4] ⇒
map dbl (filter pos [1,2,3,4]) ⇒
map dbl [2,4] ⇒ [4,8]
15/32
fold Functions

A common operation is to combine the elements of a list into


one element. Such operations are called reductions or
accumulations.
Examples:

sum [1,2,3,4,5] ≡
(1 + (2 + (3 + (4 + (5 + 0))))) ⇒ 15
concat ["H","i","!"] ≡
("H" ++ ("i" ++ ("!" ++ ""))) ⇒ "Hi!"

Notice how similar these operations are. They both combine


the elements in a list using some binary operator (+, ++),
starting out with a “seed” value (0, "").

16/32
fold Functions. . .

Haskell provides a function foldr (“fold right”) which


captures this pattern of computation.
foldr takes three arguments: a function, a seed value, and a
list.
Examples:

foldr (+) 0 [1,2,3,4,5] ⇒ 15


foldr (++) "" ["H","i","!"] ⇒ "Hi!"

foldr:

foldr :: (a->b->b) -> b -> [a] -> b


foldr f z [ ] = z
foldr f z (x:xs) = f x (foldr f z xs)

17/32
fold Functions. . .

Note how the fold process is started by combining the last


element xn with z. Hence the name seed.
foldr(⊕)z[x1 · · · xn ] = (x1 ⊕ (x2 ⊕ (· · · (xn ⊕ z))))

Several functions in the standard prelude are defined using


foldr:

and,or :: [Bool] -> Bool


and xs = foldr (&&) True xs
or xs = foldr (||) False xs

? or [True,False,False] ⇒
foldr (||) False [True,False,False] ⇒
True || (False || (False || False)) ⇒ True

18/32
fold Functions. . .

Remember that foldr binds from the right:

foldr (+) 0 [1,2,3] ⇒ (1+(2+(3+0)))

There is another function foldl that binds from the left:

foldl (+) 0 [1,2,3] ⇒ (((0+1)+2)+3)

In general:
foldl(⊕)z[x1 · · · xn ] = (((z ⊕ x1 ) ⊕ x2 ) ⊕ · · · ⊕ xn )

19/32
fold Functions. . .

In the case of (+) and many other functions

foldl(⊕)z[x1 · · · xn ] = foldr(⊕)z[x1 · · · xn ]

However, one version may be more efficient than the other.

20/32
fold Functions. . .

⊕ ⊕

x1 ⊕
⊕ xn
x2 ⊕
⊕ x3
x3
⊕ x2

xn z x1
z
foldr ⊕ z [x1 · · · xn ] foldl ⊕ z [x1 · · · xn ]

21/32
Operator Sections

We’ve already seen that it is possible to use operators to


construct new functions:
(*2) – function that doubles its argument
(>2) – function that returns True for numbers > 2.

Such partially applied operators are known as operator


sections. There are two kinds:
(op a) b = b op a

(*2) 4 = 4 * 2 = 8
(>2) 4 = 4 > 2 = True
(++ "\n") "Bart" = "Bart" ++ "\n"

22/32
Operator Sections. . .

(a op) b = a op b

(3:) [1,2] = 3 : [1,2]= [3,1,2]


(0<) 5 = 0 < 5 = True
(1/) 5 = 1/5

Examples:
(+1) – The successor function.
(/2) – The halving function.
(:[]) – The function that turns an element into a singleton
list.
More Examples:

? filter (0<) (map (+1) [-2,-1,0,1])


[1,2]
23/32
takeWhile & dropWhile

We’ve looked at the list-breaking functions drop & take:

take 2 [’a’,’b’,’c’] ⇒ [’a’,’b’]


drop 2 [’a’,’b’,’c’] ⇒ [’c’]

takeWhile and dropWhile are higher-order list-breaking


functions. They take/drop elements from a list while a
predicate is true.

takeWhile even [2,4,6,5,7,4,1] ⇒


[2,4,6]
dropWhile even [2,4,6,5,7,4,1] ⇒
[5,7,4,1]

24/32
takeWhile & dropWhile. . .

takeWhile :: (a->Bool) -> [a] -> [a]


takeWhile p [ ] = [ ]
takeWhile p (x:xs)
| p x = x : takeWhile p xs
| otherwise = [ ]

dropWhile :: (a->Bool) -> [a] -> [a]


dropWhile p [ ] = [ ]
dropWhile p (x:xs)
| p x = dropWhile p xs
| otherwise = x:xs

25/32
takeWhile & dropWhile. . .

Remove initial/final blanks from a string:

dropWhile ((==) ’ ’) " Hi!" ⇒


"Hi!"

takeWhile ((/=) ’ ’) "Hi! " ⇒


"Hi!"

26/32
Summary

Higher-order functions take functions as arguments, or return


a function as the result.
We can form a new function by applying a curried function to
some (but not all) of its arguments. This is called partial
application.
Operator sections are partially applied infix operators.

27/32
Summary. . .

The standard prelude contains many useful higher-order


functions:
map f xs creates a new list by applying the function f to
every element of a list xs.
filter p xs creates a new list by selecting only those
elements from xs that satisfy the predicate p
(i.e. (p x) should return True).
foldr f z xs reduces a list xs down to one element, by
applying the binary function f to successive
elements, starting from the right.
scanl/scanr f z xs perform the same functions as
foldr/foldl, but instead of returning only the
ultimate value they return a list of all
intermediate results.
28/32
Exercise

Exercise (a):
Define the map function using a list comprehension.
Template:

map f x = [ · · · | · · · ]

Exercise (b):
Use map to define a function lengthall xss which takes a
list of strings xss as argument and returns a list of their
lengths as result.
Examples:

? lengthall ["Ay", "Caramba!"]


[2,8]

29/32
Exercise

1 Give a accumulative recursive definition of foldl.


2 Define the minimum xs function using foldr.
3 Define a function sumsq n that returns the sum of the
squares of the numbers [1 · · · n]. Use map and foldr.
4 What does the function mystery below do?

mystery xs =
foldr (++) [] (map sing xs)
sing x = [x]

Examples:

minimum [3,4,1,5,6,3] ⇒ 1

30/32
Exercise. . .

Define a function zipp f xs ys that takes a function f and


two lists xs=[x1 , · · · , xn ] and ys=[y1 , · · · , yn ] as argument,
and returns the list [f x1 y1 , · · · , f xn yn ] as result.
If the lists are of unequal length, an error should be returned.
Examples:

zipp (+) [1,2,3] [4,5,6] ⇒ [5,7,9]

zipp (==) [1,2,3] [4,2,2] ⇒ [False,True,False]

zipp (==) [1,2,3] [4,2] ⇒ ERROR

31/32
Exercise

Define a function filterFirst p xs that removes the first


element of xs that does not have the property p.
Example:

filterFirst even [2,4,6,5,6,8,7] ⇒


[2,4,6,6,8,7]

Use filterFirst to define a function filterLast p xs


that removes the last occurence of an element of xs without
the property p.
Example:

filterLast even [2,4,6,5,6,8,7] ⇒


[2,4,6,5,6,8]

32/32

You might also like