2 Nov

Higher order functions

Functions that take other functions as arguments

Map

map transform list applies transform to each element of list

transform is a function that takes one argument and returns its transformation

double x = x + x
> map double [1, 2, 3]  -- apply the function to each element in the list
[2, 4, 6]

This way, squares defined in Lab 2 can be rewritten as:

square x = x^2

> squares l = map square l
> squares [1, 2, 3, 4]
[1, 4, 9, 16]

Filter

filter predicate list keeps only elements of list for which predicate returns True

predicate is a function that takes one argument and returns True/False

isDivisible x = x `mod` 3 == 0
> filter isDivisible [1, 2, 3, 4, 5, 6]  -- only keep elements where the function returns True
[3, 6]

This way, squareEvens defined in Lab 2 can be rewritten as:

> squareEvens l = map square (filter even l)
> squareEvens [1, 2, 3, 4]
[4, 16]

Fold

fold aggregate start list repeatedly applies aggregate to elements of list, using start as the initial value

aggregate is a function that takes two arguments and returns their combination

start is a single element, of the same type as those in list

customAdd x y = x + y + 10
> foldl customAdd 100 [1, 2, 3]  -- aggeregate elements with the given function starting with the initial value
136   -- 100(initial) + 1(first element) +10(from customAdd)   +   2 +10   +   3 +10

foldl vs foldr

Commutative:

> foldl (+) [1, 2, 3] 0  -- starting from the left
6 -- 0 + 1 ~> (0+1) + 2 ~> ((0+1)+2) + 3 ~> 6

> foldr (+) [1, 2, 3] 0  -- starting from the right
6  -- 3 + 0 ~> 2 + (3+0) ~> 1 + (2+(3+0)) ~> 6

Non-commutative:

> foldl (++) "ABC" ["xy", "zt"]  -- left
"ABCxyzt"  -- ABC ~> ABC + xy ~> ABCxy + zt ~> ABCxyzt

> foldr (++) "ABC" ["xy", "zt"]  -- right
"xyztABC" -- ABC ~> zt + ABC ~> xy + ztABC ~> xyztABC

Function composition

triple x = x * 3
add5 x = x + 5

The following definitions are equivalent:

compound x = triple(add5 (x))
compound x = (triple . add5) x
compound x = triple . add5 $ x  -- different way, less parentheses
compound = triple . add  -- ommit the argument all-together

> compound 10
45  -- add5 (becomes 15) then triple (becomes 45)

This way, the above can be shortened as:

squares = map square
squareEvens = map square . filter even

Arrow

a >>> b passes the result of a as an argument for b

Reverse order compared to . – reads more like natural language

Defined in Lab 3, can also be imported from Control.Arrow

import Control.Arrow

compound = add5 >>> triple  -- first add 5, then triple it
squareEvens = filter even >>> map square  -- first keep even numbers then square them

Lambdas and short-hands

A lambda is an anonymous function, the following are all equivalent:

> map double [1, 2, 3]
> map (\x -> x * 2) [1, 2, 3]  -- because \ kind-of looks like a little lambda
> map (*2) [1, 2, 3]  -- currying (more in later labs)

[1, 4, 9]  -- all three yield the same thing

This way, the above can be shortened as:

square = (^2)
squares = map (^2)
squareEvens = map (^2) . filter even

Pairs

A pair looks like (a, b)

> fst (1, 2)  -- access first element
1

> snd (1, 2)  -- access second element
2

uncurry transforms a function that takes two arguments into one that takes a pair

> customAdd 2 3
15 -- 2 + 3 + 10

> pairwise = uncurry customAdd
> pairwise (2, 3)
15

> uncurry (-) 10 7  -- also works for operators
3

zip creates pairs of elements from given lists:

> :t zip
zip :: [a] -> [b] -> [(a, b)]

> [1, 2, 3] `zip` [0, 0, 7]
[(1,0), (2,0), (3,7)]

> zip "abc" [0..]  -- with an infinite list
[('a',0), ('b',1), ('c',2)]