# Lecture 2 — 2018-01-18

## Higher-order functions

We spent the class discussion list functions, using anonymous functions (lambdas, written `\x1 x2 x3 ... -> e`), with a focus on maps and folds. I meant to discuss graphs but didn’t get to it—I’ve got some notes at the bottom anyway.

Before I go into detail about folds, you should know how to turn on warnings in GHC:

``{-# OPTIONS_GHC -Wall -fno-warn-unused-imports #-}``

I turn off the unused imports warning, because it’s annoying and not really relevant for us. For this file, we’ll also turn off warnings about name shadowing.

``{-# OPTIONS_GHC -fno-warn-name-shadowing #-}``

In general, though, it’s better to leave that warning on.

``````module Lec02 where

import Prelude hiding (map, foldr, foldl) -- hide some things we'll define ourselves

import Data.Map (Map)
import qualified Data.Map as Map
import Data.Set (Set)
import qualified Data.Set as Set``````

## Maps

We started by observing some patterns:

``````addOne :: [Int] -> [Int]

double :: [Int] -> [Int]
double [] = []
double (x:xs) = 2*x : double xs

negateAll :: [Bool] -> [Bool]
negateAll [] = []
negateAll (b:bs) = not b : negateAll bs``````

And abstracting out a general framework:

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

The `map` function is a higher-order function, because it’s a function that takes another function as its input. We can understand its behavior diagrammatically like so:

``````   :             :
/ \           / \
1   :        f 1  :
/ \    =>     / \
2   :        f 2  :
/ \           / \
3  []        f 3  []``````

Higher-order functions are extremely powerful: they let us express whole patterns of computation in a single fell swoop. Once we’ve written `map`, we don’t need to ever write that kind of recursion manually again. Not only do we avoid silly errors in writing map-like functions, we also save time.

## Folds

There’s some nice material on Wikipedia about folds.

There are two kinds of folds: rightwards folds and leftwards folds. They correspond to direct and accumulating recursion, respectively. Since direct is easier to understand, we looked at foldr first.

The folds we’ll define—`foldr` and `foldl` are already in the Prelude…

so we can hide them for the rest of this file.

We’ll need a few more imports below.

foldr

Here’s a rightward fold, a higher-order function that seems a bit opaque at first blush.

``````foldr :: (a -> b -> b) -> b -> [a] -> b
foldr _ b [] = b
foldr f b (a:as) = f a (foldr f b as)``````

We can understand`foldr` using the following equation:

`foldr f b [a1,...,an] = f a1 (f a2 (... (f an b) ...))`

We can also understand `foldr` as replacing a list’s ‘spine’ with function applications, like so:

``````   :             f
/ \           / \
1   :         1   f
/ \    =>     / \
2   :         2   f
/ \           / \
3  []         3   b``````

We defined a few different functions using `foldr`.

``````head :: [a] -> a
head = foldr (\a _ -> a) undefined

product :: [Int] -> Int
product = foldr (*) 1

and, or :: [Bool] -> Bool
and = foldr (&&) True
or  = foldr (||) False``````

In general, a function defined like:

``````g [] = v
g (x:xs) = f x (g xs)``````

can be implemented using `foldr` as:

``g = foldr f v``

foldl

Leftward folds are like rightward folds but using a different pattern:

``````   :                f
/ \              / \
1   :            f   3
/ \    =>    / \
2   :        f   2
/ \      / \
3  []    b   1``````

The code for a leftward fold looks more like the accumulator passing style functions we’ve already written.

``````foldl :: (b -> a -> b) -> b -> [a] -> b
foldl _ b [] = b
foldl f b (a:as) = foldl f (f b a) as``````

Correspondingly, `foldl` satisfies the following equation:

``foldl f b [a1,...,an] = f (... (f (f b a1) a2) ...) an``

We can use `foldl` to define the list reversal:

``````rev :: [a] -> [a]
rev = foldl (\acc x -> x:acc) []``````

We can also use it to easily define `last`:

``last = foldl (\a b->b) undefined ``

Finally, we can mechanically translate recursive accumulating functions defined like:

``````g xs = g' xs b

g' [] acc = acc
g' (x:xs) acc = g' xs (f x acc)``````

into leftward folds like:

``g' = foldl f b``

## Graphs

We didn’t get a chance to apply our newfound prowess with maps and folds to working with maps and sets.

Haskell’s maps and set data types (in `Data.Map` and `Data.Set`, respectively) are opaque: we don’t get to know what constructors they have, so we have no choice but to use maps, folds, and other higher-order functions to work with them.

``````type Node = String
type Graph = Map Node (Set Node)``````

Note how we (a) simulataneously assign types to a number of values while (b) simultaneously defining those values.

``````a,b,c,d,e :: Node
[a,b,c,d,e] = ["a","b","c","d","e"]``````

You can also use tuples, as in:

``````f,g :: Node
(f,g) = ("f","g")``````

Next, we can define two graphs.

``````g1,g2 :: Graph
g1 = Map.fromList [(a, Set.fromList [b,c]),
(b, Set.fromList [a,d]),
(c, Set.fromList [a,d]),
(d, Set.fromList [b,c])]
g2 = Map.fromList [(a, Set.fromList [b,c]),
(b, Set.fromList [a,d]),
(c, Set.fromList [a,d]),
(d, Set.fromList [])]``````

These correspond to the following directed graphs:

``````a ↔ b
↕   ↕    g1
c ↔ d

a ↔ b
↕   ↓    g2
c → d``````

We can easily calculate the out-degree of each node:

``````outDegrees :: Graph -> Map Node Int
outDegrees = Map.map Set.size``````

And we can just as easily check that all nodes have out-degree one or more:

``````allDegreeOneOrMore :: Graph -> Bool
allDegreeOneOrMore = Map.foldr ((&&) . (>=1)) True . outDegrees``````

We can also write a function that takes a node and a graph and makes a new graph where every node has out-degree of at least one.

``````makeDegreeOne :: Node -> Graph -> Graph
makeDegreeOne n g = Map.insert n (Set.singleton n) g'
where g' = Map.map connect g
connect tgts =
if Set.null tgts
then Set.singleton n
else tgts``````