What is currying and is it really hot?

From Wikipedia:

Curry (/ˈkʌri/, plural curries) is a dish originating in the cuisine of the Indian Subcontinent. The common feature is the use of complex combinations of spices or herbs, usually including fresh or dried hot chillies.

There are very few things I like more than spices, herbs and fresh chillies, but that is not the reason I am writing this post. Lately, what has me really fired up is functional programming - to that extent that I’m sometimes forgetting my lunch because of it!

One thing that has been bouncing around in my head is the simple fact that:

The same way a function can return any value such as 42, it can also return another function as the result.

Awesome! Wait, how is this useful?

In functional programming it is all about composing simple functions together to do one complex task. This keeps our code DRY and easy to maintain. However, from time to time we all end up writing a really long and complex function, because we have to do some heavy processing or a calculation that just looks like one big monolith.

The ability to return a function as a result of another function allows us to decompose these long monolithic functions into smaller, more managable chunks of code. Let’s see how!

Such complicated functions by nature tend to accept multiple parameters. But here is an interesting point about that:

Often we can often divide a long parameter list into 2 groups:

  1. Configuration parameters, for example:
    • Direction of sorting for a sort function
    • Dictionary for a spell checker
  2. Actual data to be processed
    • Array to be sorted
    • Words to be spell checked

Why not take advantage of this fact and try to decompose our function into 2 simpler functions, to make our life a little bit easier?

Ok, how can we do this?

Partial Function Application

Even though this sounds complicated, you can think of it as:

If we have a function that takes three arguments, we can call it with only one or two arguments, and still get a result back.

Ok, but what does it return?

It will return yet another function! We can then call this function with the rest of arguments to finish the job, and get the actual result back.

We can use this in the following way:

  1. We first pass our configuration parameters and get a simpler function back.
  2. Later we pass the data parameters, to this new function and we get the final result.

Let’s look at a really simple example to illustrate this point in code:

  • Ruby
  • Elixir
  • JS
def greeting(hi, remark)
  lambda { |person| "#{hi}, #{person}! #{remark}" }
end

ahoy = greeting("Ahoy", "Weigh anchor...")
hi   = greeting("Hi", "Let's go...")

ahoy.call("Joe") # Ahoy, Joe! Weigh anchor...
hi.call("Joe")   # Hi, Joe! Let's go...
def greeting(hi, remark) do
  fn (person) -> "#{hi}, #{person}! #{remark}" end
end

ahoy = greeting("Ahoy", "Weigh anchor...")
hi   = greeting("Hi", "Let's go...")

ahoy.("Joe")  # Ahoy, Joe! Weigh anchor...
hi.("Joe")    # Hi, Joe! Let's go...
function greeting(hi, remark) {
  return function(person) {
    return hi + ', ' + person + '! ' + remark;
  };
}

var ahoy = greeting("Ahoy", "Weigh anchor...");
var hi   = greeting("Hi", "Let's go...");

ahoy("Joe"); // Ahoy, Joe! Weigh anchor...
hi("Joe");   // Hi, Joe! Let's go...

// In JavaScript we can also achieve the same result with:
function greeting(hi, remark, person) {
  return hi + ', ' + person + '! ' + remark;
};

var ahoy = greeting.bind(null, "Ahoy", "Weigh anchor...");
ahoy("Joe"); // Ahoy, Joe! Weigh anchor...

As you can see, we first pass in the hi and the remark parameters to configure our greeting. And then we get the customized greeting function which takes only the person argument.

This is useful, because now we only need to pass the configuration parameters once, and then we can use the function many times to greet different people.

Making It Even More Modular - Currying

We all know that we must DRY our spices well, before we use them. It just happens to also be true for programming and functions.

To achieve maximum flavor, we can create a chain of functions where each takes only one parameter. Something like this:

  • Ruby
  • Elixir
  • JS
def greeting(hi)
  lambda { |remark|
    lambda { |person| "#{hi}, #{person}! #{remark}" }
  }
end

hi = greeting("Hi")
hi_lets_go = hi.call("Let's go...")
hi_you_look_nice = hi.call("You look nice...")

hi_lets_go("Joe")       # Hi, Joe! Let's go...
hi_you_look_nice("Joe") # Hi, Joe! You look nice!
def greeting(hi) do
  fn (remark) ->
    fn (person) -> "#{hi}, #{person}! #{remark}" end
  end
end

hi = greeting("Hi")
hi_lets_go = hi.("Let's go...")
hi_you_look_nice = hi.("You look nice...")

hi_lets_go("Joe")       # Hi, Joe! Let's go...
hi_you_look_nice("Joe") # Hi, Joe! You look nice!
function greeting(hi) {
  return function(remark) {
    return function(person) {
      return hi + ', ' + person + '! ' + remark;
    };
  };
}

var hi = greeting("Hi");
var hi_lets_go = hi("Let's go...");
var hi_you_look_nice = hi("You look nice...");

hi_lets_go("Joe");       # Hi, Joe! Let's go...
hi_you_look_nice("Joe"); # Hi, Joe! You look nice!

This technique is called function currying, after Haskell Curry.

Why is it better than the previous example?

Great question! The first example with partial application has one big problem - it forces us to provide both the first and the second argument at the same time.

Sometimes we may want to apply the second and the third parameter together, or maybe each one individually. Function currying gives us the freedom to do so while having only one implementation of the function.

This has proven to be so useful that many languages, like Haskell by default curry all the functions you define.

Partial Application vs. Currying

Here is a rule of thumb to quickly differentiate the two:

  • Partial application predetermines which parameters must be passed together, currying does not.
  • Currying always produces a chain of functions where each one takes only one argument, while partial application can produce functions which take any number of arguments.