12 Jun 2015
Disclaimer: There are some differences in the definition of fold and reduce in different languages - I won’t explore them here. Neither is the right / left variations of fold or reduce explained here.
Fold or reduce, from now on I will only use fold, is one of those functions which can be a bit hard to grasp when you’re new to functional programming but once you get it, it feels very natural and you end up using it all the time. A little while back I listened to a discussion about how to explain fold to novice programmers. Usually you end up drawing each iteration on a whiteboard and try to explain how the accumulator changes in each step.
But yesterday I was reading the paper Why functional programming matters and found that it explained fold in a way which I’d never seen before - perhaps that’s just me but it goes something like this:
Suppose you want to use fold on a list. First we must acknowledge that a list simply consists of many cons cells. In Scala, we can create the cons cells
used in lists with the function ::
. The function will take a value on the left hand side of the operator and another cons cell
or the “empty” Nil
value on the right hand side, and return a new cons cell
.
This is how it looks like:
// Nil is equal to the empty list.
Nil == List()
// A cons cell consisting of 1 and Nil equals a
// list with one element which has the value 1.
1 :: Nil == List(1)
// A list consisting of any number of elements can
// be created by combining multiple cons cells.
1 :: (2 :: (3 :: Nil)) == 1 :: 2 :: 3 :: Nil == List(1, 2, 3)
Now we want explain fold by creating the function sum
which sums up the elements of a list. In Scala, we can do it like this:
// Add is a function that takes two integers, a and b
// and returns the resulting a + b.
val add = (a: Int, b: Int) => a + b
// Sum is a function which takes a list of integers
// and returns the sum of all the integers using fold.
val sum = (l: List[Int]) => l.fold(0)(add)
// This is how it we can use it.
sum(List(1, 2, 3)) == 1 + 2 + 3 == 6
What the paper did, which I found interesting, is how it explains how the fold
works. As seen in the example above, fold
takes two arguments, an accumulator: 0
, and a function: add
. By using fold
on a list, we essentially replace the function ::
, which represents the cons cells
, with our specified function add
(or a + b
), and the accumulator 0
replaces the Nil value.
Or explained in code:
sum(List(1, 2, 3)) ==
sum(1 :: (2 :: (3 :: Nil))) ==
1 + (2 + (3 + 0))
A neat way to explain fold or reduce if you ask me. The paper continues and applies this concept to a tree, but you have to read that yourself if you want to know more - I highly recommend it!