Ramda for me is a library that always looked cool, but its size made me think twice about adding it to our front end. Since I recently made the switch to back end development (node.js), I have started using Ramda, and have slowly been realising its awesomeness. This guide is basically my learnings over the past couple months, with a few examples thrown in for good measure.

Auto currying

All functions in Ramda are auto-curried. This means that you can call the function with less parameters than it needs, and it will return a partially applied function. Functions will keep returning functions they have been called with their final parameter, at which point they will compute the result.

R.add(1, 2)

> 3 R.add(1)(2)

> 3 const increment = R.add(1)

> fn increment(2)

> 3

There is also a function called R.curry which will allow you to turn any normal function, into an auto-curried function.

const add = (a, b) => a + b add(1, 2)

> 3 add(1)(2)

> Uncaught TypeError: add(...) is not a function const curriedAdd = R.curry(add) curriedAdd(1, 2)

> 3 curriedAdd(1)(2)

> 3

Why is currying important?

Currying allows us to do 2 things which are important in functional programming. Namely, specialisation and composition.

Specialisation comes from the ability of curried functions to be partially applied. We can store these partially applied functions as variables to be used again later. In the example below, we can reuse partially applied versions of the addTitle function.

const bev = {name: 'Bev', gender: 'female'}

const rich = {name: 'Rich', gender: 'male'} const addTitle = (title, name) => `${title}. ${name}`

const curriedAddTitle = R.curry(addTitle)

const addMs = curriedAddTitle('Ms')

const addMr = curriedAddTitle('Mr') addMs(bev.name)

> 'Ms. Bev' addMr(rich.name)

> 'Mr. Rich'

We could then go ahead and create functions for addMrs , addMiss , addDr , and so on. By doing this, we can create a well defined interface, rather than calling addTitle with 2 arguments every time.

The other awesome thing about currying is it allows us to compose functions together more easily. We will discover how, in the next section.

Function Composition

What is function composition? According to wikipedia:

In mathematics, function composition is the pointwise application of one function to the result of another to produce a third function

In programming, we can generalise this to mean combining any number of functions together, to produce a new function. Here’s a simple example:

const increment = (x) => x + 1

const double = (x) => x * 2 const doublePlusOne = (x) => increment(double(x))

doublePlusOne(10)

> 21

Here we are creating a new function that returns the result of calling both double and increment on the value passed to it. We are composing the functions together. This looks fine, however what happens when we want to compose more than 2 functions together?

const square = (x) => x * x

const halve = (x) => x / 2 const calculateThings = (x) => halve(square(increment(double(x))))

calculateThings(10)

> 220.5

Now it is starting to look cumbersome. Not only do the brackets stack up on one side, but we need to read the function calls from right-to-left.

Pipe to the rescue

Ramda give us an awesome function called pipe . It takes any number of functions as its arguments, and returns a function that calls each of those functions sequentially to produce a result. Lets rewrite calculateThings using the pipe function.

const calculateThings = R.pipe(double, increment, square, halve) calculateThings(10) // still 220.5

pipe removes the need for all the brackets, and also lets us specify our functions in a more human readable left-to-right order.

With the exception of the first function, all functions passed to pipe must be unary functions. Since each function is being called with the result of the function before it, they will only receive one parameter each.

It’s also worth mentioning there is a function called compose which is similar to pipe , except it will call the functions in the reverse order. It’s up to you which you prefer, but pipe feels more intuitive to me.

Remember us talking about how currying makes composing functions together easier? Because Ramdas’ functions are auto-curried, we can pass partially applied calls into the pipe.

// With partially applied functions

const mathPipe = R.pipe(

R.multiply(4),

R.add(2),

R.divide(2)

) mathPipe(10)

> 21

Ramdas’ math functions add , multiply , and divide all take 2 parameters, but we are only passing the first parameter in, and the second value will get passed in through the pipe.

Partially applied functions can also be used anywhere a unary function is expected. We could for example, pass in a partially applied function as a parameter to Ramdas’ map function.

const people = ['James', 'Hadley', 'Terry', 'Trev', 'Szab']

const addTitle = R.curry((title, name) => `${title}. ${name}`) R.map(addTitle('Mr'), people);

> ['Mr. James', 'Mr. Hadley', 'Mr. Terry', 'Mr. Trev', 'Mr. Szab'] R.map(addTitle('Dr'), people);

> ['Dr. James', 'Dr. Hadley', 'Dr. Terry', 'Dr. Trev', 'Dr. Szab']

Summing up

Hopefully you have taken something useful from this article, and have enjoyed reading it as much as I’ve enjoyed writing it. Part 2 of this series is going to be about Ramda’s lens functions. Stay tuned, it will be coming up soon.