Sunday, March 2, 2014

Currying in JavaScript

"If I had a suit to
Master Shallow, I would humour his men with the
imputation of being near their master; if to his men, I
would curry with Master Shallow that no man could
better command his servants."
-- Shakespeare, Henry IV Part 2
Act V, Scene I, Lines 64.ii - 68.i

What is Currying?


Using the HaskellWiki as a dictionary.

"Currying is the process of transforming a function that takes multiple arguments into a function that takes just a single argument and returns another function if any arguments are still needed."
-- HaskellWiki

In even more detail with historical context.

"Currying has its origins in the mathematical study of functions. It was observed by Frege in 1893 that it suffices to restrict attention to functions of a single argument. For example, for any two parameter function f(x,y), there is a one parameter function f' such that f'(x) is a function that can be applied to y to give (f'(x))(y) = f (x,y)."

In other words currying allows for you to think of your functions in such a way as that they only take one argument while in fact they have many arguments.

Example, say we have the following function f.

f(x, y) = y/x

We can curry f with the argument of 2 giving us a new function h.

h(y) = y/2

We can then call h with arguments obtaining the result of dividing those values by 2.

h(4) = 2
h(10) = 5
h(2) = 1

We could also define the function f in the following way.

f(h(y),x) = y/x

Now we get the following given the argument of 2.

h(y) = y/2

Thus getting same result as above.

In Haskell Everything is Curried


"Every function in Haskell officially only takes one parameter."
-- Miran Lipovača, Learn You a Haskell for Great Good
Chapter 6


When I first read the statement above my mind was blown.  Having read nothing about currying before I could not believe what I was reading.  Everything is curried?!?  If I define a function add which takes two arguments, then that function will be curried by default!?!

Using tryhaskell.org we can do the following.


λ (\x y -> x + y)
:: Num a => a -> a -> a
λ (\x y -> x + y) 2
:: Num a => a -> a
λ (\x y -> x + y) 2 3
5
:: Num a => a

In the first line we see the lambda function(\x y -> x + y)which takes x and y this is defined as a -> a -> a where a is a Number.  If we call the exact same lambda function with one argument we get a new function defined as a -> a.  Lastly if we take the same function and apply two arguments to it we get the value back.

This is currying in action.  All the functions are really just unary functions which will either return a anothing function or a value (which you could think about as a function that does not do anything other than returning the same value every time you call it).

In JavaScript Nothing is Free


How do we curry in JavaScript?  Well JavaScript does not curry by default like Haskell does, so we will have curry our functions ourselves.



Roll Our Own


In the gist above on lines 11-17 a curry add which takes three arguments.

var ownAdd = function(a){
return function(b){
return function(c){
return a + b + c;
}
}
};

This function returns functions until it has all three arguments, once it has all three arguments it will return the sum of the arguments.  This will work but it really sucks!  Luckily currying is a well known pattern, so we have our pick of implementations of it in JavaScript like: underscore-contrib, allong.es, lemond, ...

Allong.es


Allong.es has a curry function which when applied to a function will return a curried version of the function.

var addThree = function(a, b, c){return a + b + c;},
allongesAdd = curry(addThree);

We see another version of add in the gist on lines 19 and 20.  Yes, that is a lot less work.  Even better when we look at the example tests, we see the following on 46 and 47.

expect(allongesAdd(1)(2)(3)).to.be.equal(6);
expect(allongesAdd(1, 2, 3)).to.be.equal(6); // for free!

Yes, you get to call the function in a Haskell like curried maner and allong.es does all the hard work for you.

Mapping Fun


I know this is all well and fine, but how does one use this in a typical real world manner?  Glad you asked.  I spend a lot of time in my day job working on collections of data, one way I've used currying is with higher order functions.

Say you have an array which represent the combination to your luggage (not 100% real world, but much funnier than see same thing similar with securities, orders, executions, commissions, ...).

var luggageCombination = [1, 2, 3, 4, 5],
luggageMappings = map(luggageCombination);

This works until someone accuses you having an idiots combination for your luggage, so you figured your keep your current combination but will apply a mapping function against it to have a less idiotic combination.  In allong.es every function is curried, so you can apply map against your combination and try out different functions to see which give the best result.

Using this we can square and mod 10 the values to give us the combination of 1, 4, 9, 6, 5.  Now who is the idiot!

var squared = function(x){return x * x;},
squaredMod10 = compose(function(x){return x % 10;}, squared); // Who's an idiot now?!?
expect(luggageMappings(squaredMod10)).to.be.eql([1, 4, 9, 6, 5]);

This example is really good, since we are composing our squaredMod10 function!