Saturday, June 28, 2014

Currying Explained Simply

I know there are many articles about "currying" on the web, especially aimed at JavaScript programmers.  Do we need another one?  Well last time I looked I didn't find a really easy-to-understand article about it, so let me try my best. It can be a confusing topic and I admit I have been confused myself, at least dazed. Maybe I can help you if you feel that way too.

The reason it is confusing is that most articles about it are based on the unspoken assumption that you NEED currying, regardless of your PL. But you rarely do in JavaScript.  I'll try to explain in this blog-post why not. And then you need to understand what currying is NOT, why it's not the same thing as "partial application". But I'll focus on explaining "currying" in the simplest way possible.

It is confusing to try to understand something if you don't know why you need it. And even more so if you really don't need it.  So here we go ...

Imagine your programming department has the rule that functions can only take max. one argument. You think, who would make such a silly rule. But there are programming languages where a function can take just one argument. Wink wink: Haskell, F#.  Then your manager asks you to write a piece of code that calculates the maximum of two numbers:

  function maxOfTwo (a, b) 
  { // Return a if it is bigger than b, 
    // else return b.

You're in a pickle. You're supposed to return max of two numbers, but your function can only take one argument. What to do? The answer, the secret sauce:  currying.  Curry to the rescue. Can you do it? You can, if you can write something like this:

  max (5) (22);   //  ==  22

Notice above you are not passing multiple arguments to a function.  You are doing something else. You are calling max(5) and it seems to be returning something you can pass (22) into.  This is only possible if  max(5) RETURNS A FUNCTION. Yes, functions can return functions, this is JavaScript!

So how would you write the above function 'max'?  Like this:

  function max(a)
  { return maxB;
    function maxB (b)
    { return a < b ? b : a;

Try it.  You see it works. "max(5)" returns the function 'maxB' and if you pass 22 to that, you will get the result 22.

The process of implementing 2- or more argument functions by combining 1-argument functions in this manner is called "currying". 

So is currying useful?   How often do you have 1-argument functions laying around you  want to combine in this manner, to do the job of a 2-argument function?  Maybe you do, but typically it is much simpler to write a 2-argument function to start with - if your language allows it. 

Haskell and F# don't because "pure functions can only take one argument".  But they "fake it".  If you write the equivalent of  max(a,b) in them, they automatically, behind the scenes, turn it into the form of our single-arg max(a) above. Why? That would be another blog-post. But if you program in JavaScript you don't need to know. 

If you program in Haskell or F# you never need to DO currying, it is done for you. If you program in them it's good to KNOW about it, so you know what goes on "behind the scenes".  

In JavaScript, you can forget about it. We rarely start with a two-argument function which we want to turn into two 1-argument functions.  If we already have a 2-argument function we just use it. 

The "pattern" in the max -example above is in fact a very useful JavaScript idiom. You could call it "currying" if that is the thought-process that led you to write it in that manner. But note that executing the function max() does not DO currying. The function  max() is the RESULT of you  doing currying, writing a two-argument function in the "curried form". And it is not doing 'partial application' either. That will be the topic of my next blog-post, I hope.

So what is "currying"?  Let me offer this definition:
"Currying is the process by which a function of N arguments is implemented as N single-argument functions such that first of them takes in the first argument and returns a function which takes in the 2nd argument and so on, until the Nth single-argument function finally returns the value of the multi-argument function being implemented."

 © 2014 Panu Viljamaa. All rights reserved

No comments:

Post a Comment