Welcome back ladies and gentlemen to another round of *Practical Functional Programming in JavaScript*. Today we will develop some intuition on **transformation** - a process that happens when one thing becomes another. At the most basic level, transformation is thing A becoming thing B; `A => B`

. This sort of thing happens quite a lot in programming as well as real life; you'll develop a strong foundation for functional programming if you approach problem solving from the perspective of transformations.

Here is a classic transformation: TransformerRobot => SportsCar

Here's a wikipedia definition of transformation:

transformation [of data] is the process of converting data from one format or structure into another format or structure.

Looks like transformation is a process, but what exactly is the "data" that we are converting? Here's a definition from the wikipedia article for data.

Data (treated as singular, plural, or as a mass noun) is any sequence of one or more symbols given meaning by specific act(s) of interpretation.

Data can be both singular or plural? What about poor old datum? I guess it didn't roll off the tongue so well. In any case, with this definition, we can refer to any JavaScript type as data. To illustrate, here is a list of things that we can call data.

### Just data things in JavaScript

- a number -
`1`

- an array of numbers -
`[1, 2, 3]`

- a string -
`'hello'`

- an array of strings -
`['hello', 'world']`

- an object -
`{ a: 1, b: 2, c: 3 }`

- a JSON string -
`'{"a":1,"b":2,"c":3}'`

`null`

`undefined`

I like functional programming because it inherently deals with transformations of data, aka transformations of anything, aka As becoming Bs (or hopefully, if you're a student, Bs becoming As). Pair that with JavaScript and you have transformations that come to life. We will now explore several transformations.

Here's a simple transformation of a value using a JavaScript arrow function:

```
const square = number => number ** 2
square(3) // 9
```

`square`

is a function that takes a number and transforms it into its square. number => squaredNumber. `A => B`

.

Let's move on to transformations on collections. Here is a transformation on an Array using `square`

and the built in .map function on the Array prototype.

```
const square = number => number ** 2
const map = f => array => array.map(f)
map(square)([1, 2, 3]) // [1, 4, 9]
```

To get our new Array, we `map`

or "apply" the function `square`

to each element of our original array `[1, 2, 3]`

. We haven't changed square, we've just used it on each item of an array via `map`

. In this case, we've transformed the data that is the array `[1, 2, 3]`

into another array `[1, 4, 9]`

. Putting it in terms of A and B: `map(a => b)(A) == B`

.

The following statements are equivalent

`map(square)([1, 2, 3]) == [1, 4, 9]`

`map(number => number ** 2)([1, 2, 3]) == [1, 4, 9]`

`map(number => number ** 2)(A) == B`

`map(a => b)(A) == B`

When you `map`

, all the `a`

s in `A`

have to become `b`

s in `B`

to fully convert `A`

to `B`

. This is intuition for category theory, which I won't go into too much here. Basically A and B are nodes of some arbitrary category, lets say Arrays, and `map(a => b)`

is an "arrow" that describes how you get from A to B. Since each `a`

maps one-to-one to a `b`

, we say that `map(a => b)`

is a linear transformation or bijective transformation from A to B.

Here's another kind of transformation on collections for filtering out elements from a collection. Just like `.map`

, you can find .filter on the Array prototype.

```
const isOdd = number => number % 2 === 1
const filter = f => array => array.filter(f)
filter(isOdd)([1, 2, 3]) // [1, 3]
```

When we supply the array `[1, 2, 3]`

to `filter(isOdd)`

, we get `[1, 3]`

. It's as if to say we are "filtering" the array `[1, 2, 3]`

by the function `isOdd`

. Here is how you would write `filter`

in terms of A and B: `filter(a => boolean)(A) == B`

.

The following statements are equivalent

`filter(isOdd)([1, 2, 3]) == [1, 3]`

`filter(number => number % 2 === 1)([1, 2, 3]) == [1, 3]`

`filter(number => number % 2 === 1)(A) == B`

`filter(a => boolean)(A) == B`

Unlike `map`

, `filter`

does not convert `a`

s into `b`

s. Instead, `filter`

uses boolean values derived from `a`

s given by the function `a => boolean`

to determine if the item should be in `B`

or not. If the boolean is true, include `a`

in B. Otherwise don't. The transformation `filter(a => boolean)`

transforms A into a subset of itself, B. This "filtering" transformation falls under the general transformations.

Our last transformation is a generalized way to say both `map(a => b)(A) == B`

and `filter(a => boolean)(A) == B`

. Hailing once again from the Array prototype, welcome .reduce. If you've used `reduce`

before, you may currently understand it under the following definition:

The reduce() method executes a reducer function (that you provide) on each element of the array, resulting in single output value.

I fully endorse this definition. However, it isn't quite what I need to talk about transformation. Here's my definition of reduce that fits better into our context.

The reduce() method executes a

transformationF (A => B) defined by a reducer function and initial value

All this definition says is a general formula for transformations is `reduce(reducerFunction, initialValue)`

== `F`

== `A => B`

. Here is a quick proof.

```
const reduce = (f, init) => array => array.reduce(f, init)
const sum = reduce(
(a, b) => a + b, // reducerFunction
0, // initialValue
) // F
sum( // F
[1, 2, 3, 4, 5], // A
) // 15; B
// sum([1, 2, 3, 4, 5]) == 15
// F(A) == B
// F == (A => B)
// QED.
```

It follows that `reduce(reducerFunction, initialValue)`

can express any transformation from A to B. That means both `map(a => b)(A) == B`

and `filter(a => boolean)(A) == B`

can be expressed by `reduce(reducerFunction, initialValue)(A) == B`

.

`reducerFunction`

can be expressed as `(aggregate, curValue) => nextAggregate`

. If you've used or heard of redux, you've had exposure to reducer functions.

The reducer is a pure function that takes the previous state and an action, and returns the next state.

```
(previousState, action) => nextState
```

`initialValue`

is optional, and acts as a starting value for `aggregate`

. If `initialValue`

is not provided, `aggregate`

starts as the first element of `A`

.

I will now rewrite our Array `.map`

example from before with `.reduce`

.

```
const square = number => number ** 2
// reduce(reducerFunction, initialValue)
const map = f => array => array.reduce(
(prevArray, curValue) => [...prevArray, f(curValue)], // reducerFunction
[], // initialValue
)
map(square)([1, 2, 3]) // [1, 4, 9]
// map(square)(A) == B
// F(A) == B
```

Each iteration for a given `array`

, tack on `f(curValue)`

to the end of the `prevArray`

.

Here's our previous Array `filter`

example with `reduce`

.

```
const isOdd = number => number % 2 === 1
// reduce(reducerFunction, initialValue)
const filter = f => array => array.reduce(
(prevArray, curValue) => (
f(curValue) ? [...prevArray, curValue] : prevArray
), // reducerFunction
[], // initialValue
)
filter(isOdd)([1, 2, 3]) // [1, 3]
// filter(isOdd)(A) == B
// F(A) == B
```

Each iteration for a given `array`

, tack on `curValue`

to the end of the `prevArray`

only if `f(curValue)`

is truthy.

So yeah, `reduce`

is cool and can do a lot. I should warn you that even though it's possible to write a lot of transformations in terms of reduce, `map`

and `filter`

are there for a reason. If you can do it in `map`

or `filter`

, don't use `reduce`

. That said, there are certain things even Array `.reduce`

cannot do. These things include

- reducing values of any iterable
- reducing values of an async iterable
- reducing values of an object

I think it is valuable to be able to transform these things, so I authored a functional programming library, **rubico**, with a highly optimized reduce that works on any collection. The same goes for map and filter. In addition, any functions you supply to these special transformation functions (or for that matter any function in rubico) have async and Promises handled automagically. That's because functional code that actually does stuff shouldn't care about async - it takes away from the mathiness.

I'll leave you today with some guidelines for map, filter, and reduce.

- If you want to apply a function to all elements of a collection, use
**map** - if you want to get a smaller collection from a larger collection based on some test, use
**filter** - Most everything else, use
**reduce**

I hope you enjoyed this longer-ish intro to transformation. If you have any questions or comments, please leave them below. I'll be here all week. Also you can find the rest of my articles on my profile or in the awesome resources section of rubico's github. See you next time on *Practical Functional Programming in JavaScript - Techniques for Composing Data*

## Top comments (0)