I like using compose to collapse
code into a single function. Imagine we have several functions and some data,
and would like to print full user names. Our initial code has bunch of functions
and the final "algorithm" function `printNames`

1 | function getUser(id) { |

Notice that the functions have different arity: some functions take a single
argument (`formFullName`

has arity 1), while others take several arguments
(`concat`

and `getProperty`

has arity 2).

Our goal is to collapse the function `printNames`

into a single function using `compose`

utility.
In order to compose functions, each individual function (aside from the very last one)
needs to have arity 1. This is because the return value of each previous function is going
to be passed into it.

1 | // same as foo(bar(baz(...))) |

Let us take a look at the simple case - `getProperty`

helper. It was used inside `formFullName`

to return `user.first`

and `user.last`

values.

1 | function formFullName(user) { |

We know the first argument in both invocations and can apply partial application to create two new functions with arity 1.

1 | function formFullName(user) { |

While we are applying `getProperty`

, notice that `getUser`

can be rewritten the same way.
In this case, we know the object (the second argument), but not the property (the first argument).
Since JavaScript does not have built-in application from the right, we can use a utility library

1 | const R = require('ramda') |

Let us make the code inside `formFullName`

composable.
Our biggest problem right now is the `concat`

function - it takes 2 arguments. Luckily, we
can rewrite it using R.join

1 | function concat(a, b) { // arity 2 |

How do we get a list of strings to join? By applying `first`

and `last`

property accessors
to the same `user`

object (using R.ap method). While we are at it,
let us use Ramda's built-in property access method R.prop.

1 | // original code |

Notice the great thing - since each function inside `formFullName`

has been
partially applied (using the built-in currying), each variable `first, last, spacer, ...`

points at a function with arity 1. The last line is a composable expression
`spacer(apFirstLast(R.of(user)))`

and can be rewritten

1 | return R.compose(spacer, apFirstLast, R.of)(user) |

Even better, there is a method to extract list of values from an object R.props that can replace these three lines

1 | const first = R.prop('first') // arity 1 |

1 | function formFullName(user) { |

If we can easily compose the result and our entire function is just a few lines of code, why not construct it as an expression?

1 | const formFullName = R.compose(R.join(' '), R.props(['first', 'last'])) |

If you are used to curried functions, the you are probably comfortable with the above shorthand notation. Otherwise, keeping the explicit function might be safer.

Let us transform another binary function `print`

into an unary function. Right now it
takes two arguments

1 | function print(id, s) { |

Instead of two separate arguments, let us take in a single array of values.

1 | function print(values) { |

Or simply

1 | const print = R.apply(console.log) |

Now let us print two values using an array.

1 | function printNames(ids) { |

There is a composition there!

1 | function printNames(ids) { |

We need to generate a list of values `[id, formFullName(getUser(id))]`

from a single `id`

.
This is simple if we apply a list of functions to the same value using
R.ap (the first value is produced using identity function).
We just need to transform the `id`

into list again `[id]`

to match the signature of `R.ap`

.

1 | function printNames(ids) { |

Again we have a candidate for composition - look at `R.ap([R.identity, userName])(R.of(id))`

.
Every time you see `f(g(x))`

you have found a `R.compose`

candidate.

1 | function printNames(ids) { |

And again we have at the last two lines of the function a candidate for the compose

1 | function printNames(ids) { |

which is the same as

1 | function printNames(ids) { |

Let us now plug in `userValues`

and `userName`

from each line into the next line

1 | function printNames(ids) { |

then (using white space for clarity)

1 | function printNames(ids) { |

It is a good idea to factor out the inner `forEach`

callback for clarity. Since it is just a single
compose now, we can use an expression instead of a function in this case

1 | const print = R.apply(console.log) |

We do not need an explicit print, since we are using it only inside `printName`

.

1 | const printName = R.compose( |

In the last function `printNames`

we are just iterating over a list - we can use
R.forEach for this.

1 | function printNames(ids) { |

`R.forEach`

is curried, thus it can be made into unary function right away

1 | function printNames(ids) { |

Now we can get rid of the explicit function altogether

1 | const printNames = R.forEach(printName) |

Here is our final code - much shorter than the original, and hopefully more robust (because Ramda itself has been tested thoroughly)

1 | const R = require('ramda') |

We have applied the following principles in this refactoring

- transform functions into unary ones (accepting just a single argument)
- move arguments around until the free argument is the very last one
- replace every code of the form
`f(g(x))`

with`R.compose(f, g)(x)`

expression

Once we are comfortable composing individual functions we can start using promise compositions (R.composeP) and even Monad-returning functions (R.composeK).