2018-11-18 21:50

Page 1
- Starting in Week 3, the teaching assistants have open office hours when you can drop in and ask questions about the lab assignments.
- See the schedule for the drop-in office hours on the course home page.

- 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.

`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!

- 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. - Many similar first-order functions can be replaced by one higher-order function, factoring out the difference into a function argument.

- Let's look at some illustrative examples
- Source code: HigherOrderFunctions.hs

- Sometimes the function we want to pass as an argument
to a higher-order function is already defined and has a name, e.g.
`filter``even`[1**..**5]`==`[2,4]

- But what if it isn't?
- We can solve it by defining a helper function.
`squares`**=**`map``square`[1**..**5]**where**`square``x`**=**`x``*``x`

- We can solve it by defining a helper function.
- Let's also look at some other convenient way to create functions.

- 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!

- Operators can be used as functions by omitting one operand.
5

`*`3`==`15(

`*`3) 5`==`15`map`(`*`3) [1**..**5]`==`[3,6,9,12,15]`filter`(`<`3) [1**..**5]`==`[1,2]`filter`(3`<`) [1**..**5]`==`[4,5]

- This is called
*sections*.

- 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`)

- So far we have defined functions by equations where the function parameters
appears on the left hand side.
But there is another way:
--square x = x*x

`square`**=****\**`x`**->**`x``*``x`

- If we are going to use a function only in one place, we can use it directly
without giving it a name first
`squares`**=**`map``square``numbers`**where**`square``x`**=**`x``*``x``numbers`**=**[1**..**5]`squares`**=**`map`(**\**`x`**->**`x``*``x`) [1**..**5]

- We have the same choice for functions as for any other type of 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.

- 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**

- Which of these types are equal, which are different?

- Answer: is the same as
**Int****->****Int****->****Int****Int****->**(**Int****->****Int**) - These are the same:
- A function that takes two argument
- A function that takes one argument and returns a function that takes one argument.
- Another example: function composition
(

`b`**->**`c`)**->**(`a`**->**`b`)**->**(`a`**->**`c`)(

`b`**->**`c`)**->**(`a`**->**`b`)**->**`a`**->**`c`

- Compare these types:
**Int****->****Int****->****Int**(

**Int**,**Int**)**->****Int**

- Both are in effect functions that take two s and return an
**Int**.**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 and
`curry`convert between the two forms.`uncurry`

- Such functions are called

- In math, functions are sometimes illustrated as tables (example)
( **Int**,**Int**)**->****Int**In Out (1,1) 2 (1,2) 3 (2,1) 3 (2,2) 4 **Int****->****Int****->****Int**In Out 1 In Out 1 2 2 3 2 In Out 1 3 2 4

`map`**::**(`a`**->**`b`)**->**[`a`]**->**[`b`]`map``f`[]**=**[]`map``f`(`x`**:**`xs`)**=**`f``x`**:**`map``f``xs``filter`**::**(`a`**->****Bool**)**->**[`a`]**->**[`a`]`filter``p`[]**=**[]`filter``p`(`x`**:**`xs`)**|**`p``x`**=**`x`**:**`filter``p``xs`**|**`otherwise`**=**`filter``p``xs`

`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.

`foldr``op``base`[]**=**`base``foldr``op``base`(`x`**:**`xs`)**=**`x```op```foldr``op``base``xs`- Note: is the same as
`x```f```y``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!

- 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.

- Think of (where
`foldr`(`&`)`z`is some operator) as function that`&`- replaces with
**:**, and`&` - replaces with
[]

.`z`

- replaces
`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

`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`

- 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`

- 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: the
*monomorphism restriction*in Haskell:- A definition without parameters and without a type signature is not allowed to be overloaded.

or=foldr(||)Falseand=foldr(&&)Trueconcat=foldr(++) []removeSpaces=filter(not.isSpace)unlines=foldr(\xsys->xs++"\n"++ys) []

- 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`]

- Define
`lines`**::****String****->**[**String**]

- such that
`lines`"abc\ndef\nghi\n"**=**["abc","def","ghi"]

- Generalize it to
`segments`**::**(`a`**->****Bool**)**->**[`a`]**->**[[`a`]]

- Define
`words`**::****String****->**[**String**]

- such that
`words`"abc def ghi"**=**["abc","def","ghi"]

- 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.

- 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.

- 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 *));

`pick`1**=**`fst``pick`2**=**`snd``id`**::**`a`**->**`a`