Currying Video Tutorial


In this video we will discover the principle of currying. This principle of functional programming makes it possible to transform a function which expects several arguments into a function with one argument which will return a function for the rest of the arguments.

For example this function:

function multiply (a, b, c) {
    return a * b * c
}

multiply (1, 2, 3)

Can be transformed in this way:

curry (multiply) (1) (2) (3)

It can also be done in reverse by making the first call match the last argument.

curryRight (multiply) (3) (2) (1)

What use?

Currying is not necessarily a reason that we will find systematically but it makes it possible to simplify certain operations.

function multiply (a, b) {
    return a * b
}

const double = curry (multiply) (2)

(1, 2, 3) .map (double) // Allows to double each value of the array
('1', '23', '4'). Map (curryRight (parseInt, 2) (10)) // Make sure that the parseInt will use a base 10

You can also simplify a function that expects too many arguments.

function getPropertyOrDefault (obj, property, defaultValue) {
    return obj (property) || defaultValue
}

const getPropertyOrNull = curryRight (getPropertyOrDefault) (null)
const getTotal = curryRight (getPropertyOrDefault) (0) ('total')

getTotal ({a: '3'}) // 0
getTotal ({total: 100}) // 100

Example of implementation

Now that we have seen the principle, we can wonder how this transformation will work. In JavaScript it is quite simple to implement a currying method based on apply () and bind (). We will allow our functions to accept a second argument to manually specify the number of arguments expected by the function (for example parseInt.length will send back 1 therefore we cannot rely only on this property to determine the number of parameters).

function curry (func, arity = null) {
  return function curried (... args) {
    if (args.length> = (arity || func.length)) {
      return func.apply (this, args)
    }
    return curried.bind (this, ... args)
  }
}

function curryRight (func, arity = null) {
  return function curried (... args) {
    if (args.length> = (arity || func.length)) {
      return func.apply (this, args)
    }
    return function (... args2) {
      return curried.apply (this, (... args2, ... args))
    }
  }
}