Javascript Currying

Javascript Currying

17 February 2021

Technique of converting a function that takes multiple arguments into a sequence of functions that each take a single argument is known as Currying. It means transformation of functions that translates a function from callable as f(x, y, z) into callable as f(x)(y)(z).

function curryMain(f) { // curryMain(f) does the currying transform

 return function(x) {

   return function(y) {

     return f(x, y);

   };

 };

}

// usage

function sum(x, y) {

 return x + y;

}

let curriedSum = curryMain(sum);

alert( curriedSum(1)(2) ); // 3

Implementation is straightforward: it’s just two wrappers.

  • The result of curryMain(func) is a wrapper function(x).
  • When it is called like curriedSum(1), the argument is stored in the Lexical Environment, and a new wrapper is returned function(y).
  • After that this wrapper is called with “2” as an argument, and it passes the call to the original sum.

Some more advanced implementations of currying, such as _.curry from lodash library, return a wrapper that allows a function to be called both partially and normally:

function sum(x, y) {
 return x + y;
}

let curriedSum = _.curry(sum); // using _.curry from lodash
 library
alert( curriedSum(1, 2) ); // 3, still callable normally
alert( curriedSum(1)(2) ); // 3, called partially

Why is Currying used?

To understand the benefits we need a real-life example.

Suppose we have the logging function log(date, importance, message) that formats and outputs the information. In real life projects such functions may have a lot useful features like sending logs over the network, here we’ll just use alert:

function log(date, importance, message) {
 alert(`[${date.getHours()}:${date.getMinutes()}] [${importance}] ${message}`);
}

Let’s curry it!

log = _.curry(log);

After that log works normally:

log(new Date(), "DEBUG", "some debug"); // log(a, b, c)

But also works in the curried form:

log(new Date())("DEBUG")("some debug"); // log(a)(b)(c)

We can now easily make a convenience function for current logs:

let logNow = log(new Date());

// use it

logNow("INFO", "message"); // [HH:mm] INFO message

The logNow is log with a fixed first argument, in other words “partial” or “partially applied function” for short.

We can even go further and make such convenience function for current debug logs:

let debugNow = logNow("DEBUG");
debugNow("message"); // [HH:mm] DEBUG message

So:
1. Here we didn’t lose anything after currying: log is still callable normally.
2. We can very easily generate partial functions such as for today’s logs.

search
Blog Categories
Request a quote