By: Gorm Casper
19 Aug, 2013

Introduction to using compose and autoCurry

Here’s a small introduction to why and how to use compose and autoCurry in your code.

Throughout this, I will assume you have basic understanding of how the functions found in Underscore works and how to use them.

Before we begin, open your console and play along. Write this: lt(3,2) and hit enter to check if it’s working. It should true and not complain that “lt” is undefined.

I included a small library with some functions that we will be using. Here is some documentation in case you need it.

I have also included Underscore which as you know is accessed through _, like _.map( ... ). Since I’m using cdnjs it’s a minified version of underscore, but basically you can type _.map to get underscore’s version of map, and just map to get mine.

I suggest docking the console to the right of the browser window, but that’s of course entirely up to you.

autoCurry

Let’s first talk currying, and why it’s helpful to you. First we will define a simple function (I already did this for you):

var add = function(x, y) { return x + y };

We can call it: add(2, 4) and get back 6, nothing interesting. But what if we call it with just one argument? Like this: add(2). Well, we get back NaN because it will try to add together 2 and undefined Useless. Why doesn’t it just return a function that waits for the last parameter instead? Then we could do nice stuff like this:

var addOne = add(1);

// and then use it over and over
addOne(2); // 3
addOne(5); // 6

typeof addOne;  // "function"

That’s exactly what autoCurry does. Let’s try it.

var cAdd = autoCurry(add);  // already did this for you

// and now we can use `cAdd` as above.
var addTwo = cAdd(2);
addTwo(3);  // 5

Before I tell you why this is so interesting, let’s just quickly go over cases where a function takes more than two arguments. Actually, screw that. Do it yourself. Here’s a function that I defined for you to play with:

var addXYZ = autoCurry(function(x, y, z) {
  return x+y+z;
});

Basically it will return a function until all arguments are there. When it has its three arguments it will run the function and return the result. That’s it.

Why this is useful

Let me show you by example. We have a list of numbers list = [1, 2, 3], that we wish to filter so we have only numbers that are less than 3. Great! Let’s do it the “normal” way with underscore:

var list = [1, 2, 3];
_.filter(list, function(x){ return x < 3; });   // [1, 2]

Sweet. Nothing new. Let’s abstract things just a tiny bit. Maybe we want to reuse the “less than three” function, so we pull that out.

Notice the characteristics of the function we use to filter: It takes one argument, and it returns a boolean.

var list = [1, 2, 3];
var lt3 = function(x){ return x < 3; };
_.filter(list, lt3);    // [1, 2]

But we are not quite there yet. What happened to autoCurry? Well, how about this?

var list = [1, 2, 3];
var lessThan = autoCurry(function(y, x){ return x < y; });
_.filter(list, lessThan(3));    // [1, 2]

Now we can use our “lessThan” function over and over again. What’s happening, is that we are applying one argument to our function (that takes two) and in return we get a function waiting for its last argument before it returns our boolean used to filter the list.

That’s one reason why functional programming has so many standard functions already defined. If I, as a programmer on a project, have to define petty little functions like “lessThan”, then that kind of defeats the purpose. Not quite, but it’s a valid point, hence many standard functions are already defined and curried:

var list = [1, 2, 3];
_.filter(list, lt(3))   // [1, 2]

It reads like this: “filter the list for values less than 3”. Neat.

Flippping the arguments

You may have noticed this already, but the arguments are often “flipped” from what you’re used to, when the function is curried. Let’s continue with our lt function as an example. It takes two numbers, compares them and returns a boolean. It sort of runs a check on a single number: asking “is this smaller than that?” And with currying, we can suddenly predefine the that. I personally think of it as setting up the function so it is ready to take its single argument and return its single return value (whether it be a boolean, a new list, or whatever).

This is the reason we need the that before the this. I’ll try my luck with a little diagram. Since “this” is a keyword and I don’t want to confuse you more than I already have, I’ll write tihs instead.

/*                          /--- What we are checking up against  */
lt = autoCurry( function( that, tihs ) { return tihs < that; } );
/*                                \--- Our only "real" argument   */

And one more...

/*
    /----- This is creating a new anonymous function that
   |       checks if something is less than 3
/-----\                                               */
lt( 3 )( 2 );
/*     \---/
         \----- With this we are calling our new anonymous
                function with one arugument: 2        */

Whether we call it like lt(3, 2) or lt(3)(2) does not matter.

So let’s flip them

We have looked the function lt, but this technique is usable for any function that takes a fixed number of arguments. Let’s return to filter again. Here are underscores version and one where I flipped the arguments. (I will ignore that filter can work on objects and in some cases take more than just two arguments.)

// underscore
_.filter = function( array, func ) { ... };

// flipped (and let’s just assume autoCurried as well)
filter = function( func, array ) { ... };

So, exactly like with lt, we can easily and quickly build a new function using currying that filters a list for items less than 3:

var filterLessThan3 = filter( lt(3) );
// Both `filter` and `lt` are now curried functions waiting
// for their last argument before returning a value

// and we use it...
var list = [1, 2, 3];
filterLessThan3( list );    // [1, 2]

This is entirely impossible with underscore’s implementation of the core functions. Even if we were to curry every single one of them, the arguments would still be in the wrong order.

Let’s put it together

So let’s look at an example with some other functions. We have a list of people that are each represented by a list of attributes:

var people = [
  ["Bob Roberts", 31, "m"],
  ["Julia Smith", 63, "f"],
  ["Ken Paulsen", 23, "m"],
  ["Lisa Erikson", 9, "f"]
];

We don’t like lists, we want objects instead. We want a list of objects that looks something like this:

{
  name: "Bob Roberts",
  age: 31,
  gender: "m"
}

Good thing we have listsToObj (doc). Let’s have a look at it:

listsToObj(["a", "b", "c"], [1, 2, 3])   // {a: 1, b: 2, c: 3}

So if we curry it with a predefined list, we get something we can use:

var makeObj = listsToObj( ["name", "age", "gender"] );

makeObj( ["Bob Roberts", 31, "m"] );
// { name: "Bob Roberts", age: 31, gender: "m" }

So why don’t we just map makeObj over the entire list and we will get a list of the objects that we want?

var betterPeople = map( listsToObj( ["name", "age", "gender"] ), people );
/* →
[
  {"name":"Bob Roberts","age":31,"gender":"m"},
  {"name":"Julia Smith","age":63,"gender":"f"},
  {"name":"Ken Paulsen","age":23,"gender":"m"},
  {"name":"Lisa Erikson","age":9,"gender":"f"}
]
*/

Or how about we use the fact that map is also autoCurried and create a “makeBetterPeople” function for reuse?

var makeBetterPeople = map( listsToObj( ["name", "age", "gender"] ) );

// and we use it...
makeBetterPeople(people);     // same list of objects

That’s it! That’s autoCurrying. Next up is compose which is infinitely easier to grasp.

compose

Let me first say that compose itself is not curried since it takes an optional number of arguments... But it works very well with other curried functions. Here is what it does:

// If we have a function f(x) and g(x), and do
h = compose(f, g);
// then that is equivalent to
h = f(g(x));
// or "first take g of x, and then pass the return value of that into f"

Notice, that these functions should only accept one argument (at least the outer function, f, should), since the previous function can only return one value at a time.

Example (where I ignore currying completely):

// First we define two functions:
var add1   = function(x) { return x+1 };
var double = function(x) { return x*2 };

// Then we compose them together.
// Notice that compose begins with the last function
var add1AndDouble = compose(double, add1);

add1AndDouble(2);   // 6  --  (2+1)*2

And that’s it. That’s compose. Together with autoCurrying it becomes very powerful. If we add pick (doc) and dot (doc) to our arsenal we can do:

var getNameAndGenderOfPeopleAbove30 = compose(
  map( pick(["name", "gender"]) ),
  filter( compose( gt(30), dot("age") ) ),
  map( listsToObj(["name", "age", "gender"]) )
);

getNameAndGenderOfPeopleAbove30(people);
// [{"name":"Bob Roberts","gender":"m"},{"name":"Julia Smith","gender":"f"}]

That is pretty powerful and complex. Let me annotate it. Same exact function.

// We compose a function of three subfunctions. They will be run from bottom up
// and you should read them in that order too.
var getNameAndGenderOfPeopleAbove30 = compose(

  // Step 3: Pick only takes an object, so we map pick over
  // our object created in Step 1 (and filtered in step 2)
  // to pick out just the parts we want.
  map( pick(["name", "gender"]) ),

  // Step 2: We compose a subsubfunction that filter can use:
  // It takes whatever is passed in (an object representing
  // a person), and takes the `.age` of it and passes it into
  // `gt(30)` which returns a boolean: true if the age is
  // greater than 30, and false if not. This subsubfunction
  // is used for filtering.
  filter(
    compose(  gt(30),     // 2: returns ( age > 30 ) of age (a boolean)
              dot("age")  // 1: returns person.age of person
    )
  ),

  // Step 1: Make a list of objects like we did earlier.
  map( listsToObj(["name", "age", "gender"]) )
);

getNameAndGenderOfPeopleAbove30(people);
// [{"name":"Bob Roberts","gender":"m"},{"name":"Julia Smith","gender":"f"}]

Of course functions doesn’t have to be curried to be part of compose. Here we find the average the age of people by using two new functions: pluck (doc) and mean (doc). mean only takes a single argument, so it doesn’t make sense to curry.

var getAvgAgeOfPeople = compose(
  mean,                                         // 3: takes the mean of a list of numbers
  pluck("age"),                                 // 2: [31, 63, 23, 9]
  map( listsToObj(["name", "age", "gender"]) )  // 1: Get our objects
);

getAvgAgeOfPeople(people);                      // 31.5

And that’s it! Go home we are done here for today. Go home and play around some more with this, it really is powerful.