/ javascript

Spicy JavaScript with currying

This is not a post about functional programming in JavaScript. It's just about one lovely technique 🐬.

Haskell Brooks Curry, was an American mathematican so influencing for functional programming that there is three languages named after him. Of course, the most popular one is Haskell ❀.
haskell-brooks-curry-the-boss

Currying is a technique used for transforming functions into a sequence of functions.

How it works?

It's a simple technique for transforming multi-argument functions in such a way that it can be called as a chain of functions, each with a single argument. source.

Imagine in the following example that curriedFunction is a curried function (duh!), that simple returns a console.log of two arguments.

curriedFunction('yello', 'world');
// -> 'yello world'

curriedFunction('yello')('world');
// -> 'yello world'

Also, since the function will be evaluated once all the arguments are met. You can do this:

var stillPartial = curriedFunction('yello');
// -> The value of `res` is a function that takes one argument and executes a `console.log`.

stillPartial('world');
// -> 'yello world'

Yet JavaScript doesn't support currying out of the box. But worrying you should not! We can easily achieve it.

Haskell is magic where all functions have only one argument, of course they are all curried. Yep.

How to make it?

Let's start with a basic example.

// Non-curried `sum` function.
var sum = function(a, b) {
  return a + b;
};

You can call sum(1, 2) to get 3 but what about sum(1)(2)? It will raise a TypeError because b is undefined therefore it the first call will return NaN and the chain will try to evaluate NaN(2) and since NaN is not a function... Aha! TypeError!

So really, how to make it?

Well, the first simple solution for this would be to define an anonymous function inside the sum body. Like this:

// Curried function with one argument scrict.
var sum = function(a) {
  return function(b) {
    return a + b;
  };
};

Here, you can call get 3 by calling sum(1)(2). Great! But... what about sum(1, 2)? Yeah, that doesn't work anymore (Γ—_Γ—;. Let's fix that:

// Curried function.
var sum = function(a) {
  if (arguments.length > 1) {
    return sum(a)(arguments[1]);
  }

  return function(b) {
    return a + b;
  };
};

Now you can call sum(1, 2) and sum(1)(2) as well and both will return the same result.

louie-ck-wow
Yeah, I agree with your sarcastic "wow" Louie C.K.

This definitely looks archaic. Lucky as, there are libraries to help us wrapping those functions.

Libraries to the rescue

Lodash. One of the feature I prefer it over Underscore.

Lodash has a very good curry method that you can call like this:

var sum = _.curry(function(a, b) {
  return a + b;
});

sum(1, 2);
// -> 3

sum(1)(2);
// -> 3

Lodash is so good you could only require his curry function if you like. See: https://www.npmjs.com/package/lodash.curry

Ramda. I thank my friend @nachoaivarez for pointing me this awesome library.

Does the same as lodash.

var sum = R.curry(function(a, b) {
  return a + b;
});

sum(1, 2);
// -> 3

sum(1)(2);
// -> 3

It looks pretty convenient to just use a library. That's because it is! Just use them!

Modern uses

Async is a popular library with "Async utilities for node and the browser". async.parallel is a method that execute multiple functions at the same time.

You can do stuff like the following:

var async = require('async');

var doAsync1 = function(done) {
  // ...
  done(null);
};

var doAsync2 = function(done) {
  // ...
  done(null);
};

module.exports = function(request, response) {
  async.parallel([doAsync1, doAsync2], function(err, results) {
    if (err) {
      return response.send('=(');
    }

    response.send('ok');
  });
};

But what if I want to send extra parameters to doAsync1? Currying!

var _ = require('lodash');
var async = require('async');

var doAsync1 = _.curry(function(value1, done) {
  // ...
  done(null);
});

var doAsync2 = function(done) {
  // ...
  done(null);
};

module.exports = function(request, response) {
  async.parallel([doAsync1(request.query.userInput), doAsync2], function(err, results) {
    if (err) {
      return response.send('=(');
    }

    response.send('ok');
  });
};

Bonus track: placeholders

var _ = require('lodash');

var log = _.curry(function(w1, w2) {
  console.log(w1, w2);
});

log(_, 'world')('hello');
// -> 'hello world'

Both libraries mentioned support this, the _ will act as a placeholder which value will be defined later.

One step closer to functional programming.

lambda-function