Higher order functions are functions which operate on other functions, either taking another function as a parameter, or returning one as a result

The process of currying, discussed earlier, is a higher order function, as a function takes a parameter, and returns another functioned, specialised by that parameter

Sections

Sections are partial applications of infix operators. If you give only one argument to an infix operator, it returns a function of the “missing” side of the operation, for example, if the left side of the infix exponent is given, a function taking the exponent as the parameter is returned, but if the right side is given, the function takes the base as parameter. This is written as:

> (^2)
\x -> x ^ 2

> (2^)
\x -> 2 ^ x

Examples of higher order functions

Map

A function that takes a list and a function, and returns a new list, with every element in the old one having had the function applied to it

map :: (a -> b) -> [a] -> [b]  
map _ [] = []  
map f (x:xs) = f x : map f xs  

Filter

A function that takes a list and a predicate (a function which indicates the truth value of its parameter), and returns the list containing only the true values in the original list

filter :: (a -> Bool) -> [a] -> [a]  
filter _ [] = []  
filter p (x:xs)   
    | p x       = x : filter p xs  
    | otherwise = filter p xs  

Quicksort using filter

We can neatly write sorting algorithms using this, such as quicksort (with the pivot being picked as the middle in this case)

quicksort :: (Ord a) => [a] -> [a]    
quicksort [] = []    
quicksort (x:xs) =     
    let smallerSorted = quicksort (filter (<=x) xs)  
        biggerSorted = quicksort (filter (>x) xs)   
    in  smallerSorted ++ [x] ++ biggerSorted  

Folds

Folds are a class of function which repeatedly reduce a list, having an accumulator value, and a function which takes values from the list elementwise, and combines them into the accumulator. It is described in a stack overflow answer as:

In:
    initial value
    way to combine stuff with initial value
    collection
Out:
    combined stuff

We actually write this in code using the following syntax

initialAccumulator :: a
combinationFunction :: a -> a -> a

foo :: [a] -> a
foo xs = foldr (\accumulator x -> combinationFunction accumulator x) initialAccumulator xs

There are two common implementations, foldl, and foldr, which start by applying the function to the first and last elements respectively. These two folds have different properties, and there is an additional type foldl', which strengthens the properties of foldl. Additional source #1 Additional source #2

Foldr

foldr generates the entire expression before evaluation, with foldr f z [1,2,3] evaluating to f 1 (f 2 (f 3 z))

For example foldr (+) [1..1000] evaluates as 1 + (2 + (3 + (...))). As the chain of operations doesn’t contain a redex (reducible expression) until the entire chain is built, the entire expression must be generated before it can be evaluated. This means it will cause stack overflows on large lists.

If the combination function is able to produce part of the result independent of the recursive case, so the rest of the result is never demanded, the recursion will stop, allowing use on infinite lists

foldr (\acc x -> acc + x) 0 [3,5,2,1]
=> foldr (\acc x -> acc + x) (0+1) [3,5,2]
=> foldr (\acc x -> acc + x) (2+(0+1)) [3,5]
=> foldr (\acc x -> acc + x) (5+(2+(0+1))) [3]
=> foldr (\acc x -> acc + x) (3+(5+(2+(0+1)))) []
=> (3+(5+(2+(0+1))))

Foldl

foldl applies the function as it goes along, with foldl f z [1,2,3] evaluating to f (f (f z 1) 2) 3

For example foldl (+) [1..1000] evaluates as (((0 + 1) + 2) + 3) + .... This seems like it would reduce as is goes along, as each bracket is its own redex, but due to Haskell’s lazy evaluation, it doesn’t, so it still causes stack overflows on large lists. It can never handle infinite lists, and will always recurse forever if they are given

An example case of execution is:

foldl (\acc x -> acc + x) 0 [3,5,2,1]
=> foldl (\acc x -> acc + x) (0+3) [5,2,1]
=> foldl (\acc x -> acc + x) ((0+3)+5) [2,1]
=> foldl (\acc x -> acc + x) (((0+3)+5)+2) [1]
=> foldl (\acc x -> acc + x) ((((0+3)+5)+2)+1) []
=> ((((0+3)+5)+2)+1)

Foldl’

foldl' is a modification of foldl which forces Haskell to evaluate each redex as it goes, despite lazy evaluation, allowing avoiding stack overflows for large lists, but inherently sacrificing the other benefits of lazy evaluation

An example case of execution is:

foldl (\acc x -> acc + x) 0 [3,5,2,1]
=> foldl (\acc x -> acc + x) (0+3) [5,2,1]
=> foldl (\acc x -> acc + x) 3 [5,2,1]
=> foldl (\acc x -> acc + x) (3+5) [2,1]
=> foldl (\acc x -> acc + x) 8 [2,1]
=> foldl (\acc x -> acc + x) (8+2) [1]
=> foldl (\acc x -> acc + x) 10 [1]
=> foldl (\acc x -> acc + x) (10+1) []
=> 11

We can see this differs from the standard foldl, as at each step it reduces the accumulated expression

Function composition

A function which chains the output of one function into the input of the other

(.) :: (b -> c) -> (a -> b) -> a -> c
(.) f g x = f (g x)

We can then use this to write code more neatly with fewer brackets, for example, the following statments are equivalent:

f (g (h x))
f . g . h x