Reducing a List to a Single Value

The map/2 function we just wrote abstracts the idea of applying a function to each element of a list independently.

But what if we want to apply that function across the elements? How could we create an abstraction that would let us sum a list, or find the product of its elements, or find the largest element?

The sum function reduces a collection to a single value. Other functions need to do something similar—return the greatest/least value, the product of the elements, a string containing a concatenation of elements, and so on. How can we write a general-purpose function that reduces a collection to a value?

We know it has to take a collection. We also know we need to pass in some initial value (just like our sum/1 function passed a 0 as an initial value to its helper). Additionally, we need to pass in a function that takes the current value of the reduction along with the next element of the collection, and returns the next value of the reduction. So, it looks like our reduce function will be called with three arguments:

 reduce(collection, initial_value, fun)

Now let’s think about the recursive design:

reduce applies the function to the list’s head and the current value, and passes the result as the new current value when reducing the list’s tail.

Here’s our code for reduce. See how closely it follows the design:

lists/reduce.exs
 defmodule​ MyList ​do
 def​ reduce([], value, _) ​do
  value
 end
 def​ reduce([head | tail], value, func) ​do
  reduce(tail, func.(head, value), func)
 end
 end

And, again, we can use the shorthand notation to pass in the function:

 iex>​ c ​"​​reduce.exs"
 [MyList]
 iex>​ MyList.reduce([1,2,3,4,5], 0, &(&1 + &2))
 15
 iex>​ MyList.reduce([1,2,3,4,5], 1, &(&1 * &2))
 120