Reduce Everything! Explaining the Reduce Function

Diario del capitán, fecha estelar d459.y38/AB

I believe reduce is the single most important functional programming concept and function. Let's see why!

Small red leaf - Photo by Ksenia Makagonova on Unsplash

In this post, I'm going to explain how the reduce function works. First of all, it's called "reduce" because it reduces a collection of values into a single one, and it is available in all modern programming languages.

Let's start with an example. Here's how to reduce an array of numbers into its sum using javascript:

[1, 2, 3, 4].reduce((sum, value) => sum + value, 0) // => 10

And here you will see its equivalent in the beautiful Ruby expressiveness:

[1, 2, 3, 4].reduce(0, :+) # => 10

The reducer

Notice that arguments are the same in both examples, but in a different order. The reduce function always requires two parameters: an initial value and a reducer. Well, this is not strictly true: the initial value can be the first value of the collection.

A reducer is a function that, given a previous value (or the initial value) and an item from a collection, returns the next value.

This is the reducer from the previous example in javascript:

// the reducer:
const add = (a, b) => a + b;

// reduce:
[1, 2, 3, 4].reduce(add, 0); // => 10

Of course, in Ruby the reducer is just + 👏

Reduce everything!

One important detail of reduce is that the values of the collection and the result do NOT have to belong to the same type. Furthermore, the result doesn't have to be a single object, even.

You can reduce a list of numbers into an object, a list into another list (with elements of different types) or whatever you imagine (stream of events into http calls, even).

This versatility makes it the most important function because it allows the implementation of any other enumerable function using it as a base.

Don't believe me? You can write any enum function with reduce, but the opposite is not possible. That's why reduce is the mother of all enum functions.

For example, the following is map implemented with reduce in both javascript and Ruby languages:

Javascript:

const map = (array, fn) => array.reduce((result, item) => {
  result.push(fn(item));
  return result;
}, []);

// usage:
map([1, 2, 3, 4, 5], (n) => n * n)  // => [1, 4, 9, 16, 25]

Ruby:

def map(enumerable)
  enumerable.reduce([]) {|total, current| total << yield(current)}
end

# usage:
map([1, 2, 3, 4, 5]) {|n| n * n} # => [1, 4, 9, 16, 25]

Versioning

One popular and easy way to implement versioning in data stores is by saving, not all the values, but the difference between the current and the next. Storing the change, the update, the action, the event… git, for example, uses this technique.

With this kind of data stores you end with an enormous list of changes.

The point is that you can get the actual value at any moment of time just by following the changes from the very beginning to the time you want. How? By reducing the changes.

With an appropriate reducer you can reduce a collection of "updates" into a single value at any point in time. It's not performant but it's easy.

State + Reduce = redux

Now, imagine that the initial value is a state. It could be the state of a UI component or the state of a whole app. Both examples work in this case.

You have an initial state and a collection of (user) events. With the appropriate reducer you can obtain the current state at any point.

That's what redux is all about. You just have to write the appropriate reducer: a function that, given a current state and a (user) event (called "action" in redux), returns the next state.

redux just reduces a collection of actions into the current (app) state, and it makes easier for us to write that reducer (using composition).

And by the way, you get time traveling debugging for free.

Daniel Gómez

Daniel Gómez

Dani tuvo un Oric 1 como primer ordenador, al menos hace 100 años. Ahora combina la programación con sus dos bandas y sus tres hijos. La leyenda dice que tiene un hermano gemelo idéntico y que trabajan como equipo.

comments powered by Disqus

Estás a un paso de conocer a tu mejor socio.

Hablemos