Page 1

Page 2

# What is a higher order function?

• It's a function that takes another function as an argument.
• `even 1` False `even 2` True `map even [1,2,3,4,5]` [False,True,False,True,False] `filter even [1,2,3,4,5]` [2,4]
• `even` is a first-order function.
• `map` and `filter` are higher-order functions.
Page 3

# The types of higher order functions

• ```map    :: (a -> b)    -> [a] -> [b]
filter :: (a -> Bool) -> [a] -> [a]
```
• The first argument is a function in both cases.
• They are also polymorphic. This is a powerful combination!
Page 4

# Is this a big deal?

• Yes!
• Higher-order functions are the "heart and soul" of functional programming!
• A higher-order function can be much more versatile than a first-order function, because a part of its behaviour can be controlled by the caller.
• We can replace many similar first-order functions by one higher-order function, factoring out the difference into a function argument.
Page 5

# Functions returning functions?

• If passing functions as arguments is powerful, how about returning functions as results?
• Compare these types:
• `Int -> Int -> Int`
• `Int -> (Int -> Int)`
• `(Int -> Int) -> Int`
• Quiz: how many arguments does the following functions have?
• ```pick 1 = fst
pick 2 = snd```
• `id :: a -> a`
Page 6

# Curried functions

## Compare these types:

• `Int -> Int -> Int`
• `(Int,Int) -> Int`
• Both are in effect functions that take two
`Int`
s and return an
`Int`
.
• We have seen that Haskell favours the first variant.
• Such functions are called curried functions, after the logician Haskell Curry.
• Incidentally (or not) the Haskell language is also named after Haskell Curry.
• The predefined functions
`curry`
and
`uncurry`
convert between the two forms.
Page 7

Page 8

# Case study: sums and products of lists

• ```sum []     = 0
sum (x:xs) = x + sum xs```
• ```product []     = 1
product (x:xs) = x * product xs```
• Common pattern: combining the elements of a list with an operator
• Differences: the operator and the base case.
Page 9

# Factoring out the differences

• ```foldr op base [] = base
foldr op base (x:xs) = x `op` foldr op base xs```
• Note:
`x `f` y`
is the same as
`f x y`
• What is the type of foldr?
• `foldr :: (a -> b -> b) -> b -> [a] -> b`
• `foldr` is also known as reduce. You already know `map`, so now you know the essence of MapReduce!
Page 10

# Code reuse

• We can now simplify the definitions of sum and product.
• ```sum     xs = foldr (+) 0 xs
product xs = foldr (*) 1 xs```
• And `foldr` is useful in many more cases!
• ```or     xs = foldr (||) False xs
and    xs = foldr (&&) True xs
concat xs = foldr (++) [] xs

maximum (x:xs) = foldr max x xs```
• These are all examples of predefined functions in Haskell.
Page 11

• Think of
`foldr (&) z`
(where
`&`
is some operator) as function that • replaces
`:`
with
`&`
, and
• replaces
`[]`
with
`z`
.
• `            xs == a : b : c : d : … : []`

`foldr (&) z xs == a & b & c & d & … & z`

`foldr (+) 0 xs == a + b + c + d + … + 0`

`foldr (*) 1 xs == a * b * c * d * … * 1`
Page 12

# Quiz

## What does these function do?

• `f1 xs = foldr (:) [] xs`
• `f2 xs ys = foldr (:) ys xs`
• ```f3 xs = foldr snoc [] xs
where snoc x ys = ys++[x]
```
• ```f4 f xs = foldr fc [] xs
where fc x ys = f x:ys```
Page 13

# Passing functions as arguments

• Sometimes the function we want to pass as an argument to a higher-order function hasn't been defined.
• We can solve it by naming and defining a helper function (as in f3 above).
• Let's also look at some other convenient way to create functions.
Page 14

# Partial application

• We can apply functions to "too few" arguments
• `take 2 "Haskell"` "Ha" `map (take 2) ["Hello","Haskell"]` ["He","Ha"]
• The advantage with curried functions reveals itself!
Page 15

# Partial application of infix operators

• Operators can be used as functions by omitting one operand.
• `(*3) 5 == 15`
• `map (*3) [1..5] == [3,6,9,12,15]`
• `filter (>3) [1..5] == [4,5]`
• `filter (3>) [1..5] == [1,2]`
• This is called sections.
Page 16

# Function composition

• Example: remove white space from a string
• `removeSpaces "abc def \n ghi" = "abcdefghi"`
• We can use `isSpace` from module `Data.Char`,
• `removeSpaces s = filter (not . isSpace) s`
• Function composition is defined as
• ```(f . g) x = f (g x)
```
• What is the type of (.)?
`(b->c)->(a->b)->(a->c)`
Page 17

# Anonymous functions

• So far we have defined functions by equations where the function parameters appears on the left hand side.
• ```snoc y ys = ys++[y]
```
• But there is another way
• ```snoc = \ y ys -> ys++[y]
```
• If we are going to use a function only in one place, we can use it directly without giving it a name first
• ```f3 xs = foldr snoc [] xs
where snoc y ys = ys++[y]
```
• `f3 xs = foldr (\ y ys -> ys++[y]) [] xs`
• We have the same choice for functions as for any other value.
• The \ is supposed to look a bit like a λ (the greek letter lambda) and comes from the λ-calculus, where functions are always written in this way.
Page 18

# Example

• Combine a list of lines into a string with newline characters:
• `unlines ["abc","def","ghi"] = "abc\ndef\nghi\n"`
• One-line definition:
• `unlines ls = foldr (\xs ys->xs++"\n"++ys) [] ls`
• or with a named helper function:
• ```unlines ls = foldr join [] ls
where join xs ys = xs ++ "\n" ++ ys```
Page 19

# Eta conversion

• Consider definitions of the form
• `f x = g x`
• We are saying that f is the same function as g. This can be said in a simpler way
• `f = g`
• This is called Eta (η) conversion/reduction/expansion.
• Caveat: remember the monomorphism restrictions:
• A definition without parameters and without a type signature is not allowed to be overloaded
Page 20

# Eta conversion examples

```or     = foldr (||) False
and    = foldr (&&) True
concat = foldr (++) []

removeSpaces = filter (not . isSpace)

unlines = foldr (\xs ys->xs++"\n"++ys) []
```
Page 21

# More standard higher-order functions

• Define
• `takeLine :: String -> String`
• such that
• `takeLine "abc\ndef\nghi\n" = "abc"`
• Generalize it to
• ```takeWhile :: (a->Bool) -> [a] -> [a]
```
• Also define the complementary
• ```dropWhile :: (a->Bool) -> [a] -> [a]
```
Page 22

# Lines

• Define
• ```lines :: String -> [String]
```
• such that
• ```lines "abc\ndef\nghi\n" = ["abc","def","ghi"]
```
• Generalize it to
• ```segments :: (a->Bool) -> [a] -> [[a]]
```
Page 23

# Words

• Define
• ```words :: String -> [String]
```
• such that
• ```words "abc def  ghi" = ["abc","def","ghi"]
```
Page 24

# A bigger example: word counting

• Define a function that counts how many times words occur in a text and displays each word with its count.
• `wordCounts :: String -> String`
• `putStr (wordCounts "hello clouds\nhello sky")` clouds: 1 hello: 2 sky: 1
• Source code: HigherOrderFunctions.hs, towards the bottom of the file.
Page 25

# Lessons

• Higher-order functions take functions as arguments, making them flexible and useful in many situations.
• By writing higher-order functions to capture common patterns, we can reduce the amount of code we need to write dramatically.
• Anonymous functions, partial applications, function composition and sections help us create functions to pass as arguments, often eliminating the need for a separate function definition.
• Haskell provides many useful higher-order functions;
• break problems into small parts, each of which can be solved by an existing function.
Page 26

# Higher order functions in other languages?

• Consider these generic sorting functions in Haskell:
• ```sort   :: Ord a            => [a] -> [a]
sortBy :: (a->a->Ordering) -> [a] -> [a]
```
• Compare with a generic sorting function in C:
• void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));