Currying

Not the food from India


28 Jul 2018 View Comments
#functional #programming #software #computer #currying #partial #application

Currying done for multiplication
Currying done for multiplication


In both mathematical and programming world, the term “Currying” is often mentioned as the process of transforming a function which takes multiple arguments into a sequence of functions that each has only a single parameter. In other words, it describes that every function essentially is mapped to an expression that consists of anonymous functions, nested anonymous functions and each taking just one parameter.

The concept of “Currying” may be explained simpler by showing you the following comparisons.

In programming, “Currying” could mean as simple as,

result = f(x)(y)(z)

which mathematically is pretty much same as writing,

f1 = f(x), f2 = f1(y), result = f2(z)

Note how the function breaks down into a multiple of one-argument functions which each gets executed separately in all in a single call of “Currying” (first code).

Let us dive into an example right away. We are going to write a function called sum to describe both the concept of “Currying” and “partially applied function”. Partially applied functions are important to be mentioned here along with Currying because they consist of similar concepts but not exactly the same.

sum function is a great example to show “Currying” behaviour because the function could be used in different ways of summing such as multiplications, additions, divisions, subtractions, representing other complex values. This is the key of “Currying”. This chameleon-like sum function can be applied to various different situations which leave us room for organizing/refactoring the codes.

Let’s initially define the sum function like this below.

def sum(f: Int => Int, a: Int, b: Int): Int =
   if (a>b) 0 
   else f(a) + sum(f, a+1,b)

Now we can define the following functions which use the generic sum function we defined above.

sumInts(a:Int, b: Int) = sum(x => x, a, b)
sumCubes(a: Int, b: Int) = sum(x => x*x*x, a, b)

You may have noticed that above functions have repeated a and b parameters which get passed into our sum function. They seem to be unnecessary and can probably be simpler.

Could there be a way to remove these out? There must be a way to simplify the above functions. Well, that’s when the technique of “Currying” applies. Let me show you a step-by-step of the transformation we could make to simplify this using “Currying”.

Let’s update our sum function to return a function instead, (Int, Int) => Int.

def sum(f: Int => Int): (Int, Int) => Int = {
   def sumF(a:Int, b:Int): Int = 
      if (a>b) 0 
      else f(a) + sumF(a+1,b)
   sumF
}

When we’ve done that, we can simply define sumInts and sumCubes as themselves a function.

val sumInts = sum(x => x)
val sumCubes = sum(x => x*x*x)

where we can use it like below. It will aggregate values from 1 to 5 (15) and add it to the aggregate of cubed values from 3 to 5 (216) which would be equal to 15+216=231.

sumInts(1,5) + sumCubes(3,5)

Now can we avoid even these names sumInts and sumCubes and straight use our sum function instead? After all, they are basically using the core function, sum. The answer is “Yes” and that is where “Currying” kicks in.

We can pass in a function to our sum with values attached beside the function which is equivalent to sumInts(1,5) + sumCubes(3,5) we defined above like this.

sum(x => x)(1,5) + sum(x => x*x*x)(3,5)

This is what the Currying is in a nutshell. Being able to pass in different sets of parameters to execute the function in a specific way we want it function.

We have analyzed a rather a long explained step-by-step example of Currying above. To simply put, you could think of a function like this doSomething(10,“Hello”, true) which essentially is doSomething(10)(“Hello”)(true). It basically is calling doSomething function with anonymous functions 3 times.

I’ve mentioned above there are subtle differences between “Currying” and “Partially applied functions”. They are very similar but not exactly the same. Partial application is slightly different from Currying in that it takes the argument(s), applies it partially and returns a new function without the passed parameter. To see what it means, I will show an example using the exactly the same example as above. Let’s make a new rule (for argument sake) that the above sum function gets an upper bound of fixed 5.

val sumTo5 = sum(x=>x)(_:Int,5)
val sumCubesTo5 = sum(x=>x*x*x)(_:Int,5)

We have partially created a function here which can take a lower bound as any inputs but has fixed upper bound of 5. To apply this partially created function,

sumTo5(1) + sumCubesTo5(3) // will output 231 as well

At this point, you might wonder, what is the advantage of doing all this? To be honest, I have not come across a time where I was absolutely required to use Currying to make something work. This is probably why a lot of people thinks Currying is just another syntactic sugar for functional programming. I do not disagree. It could well be a syntactic sugar despite a possible grain of performance gains which may not even be noticeable. However, Currying is still an important concept to understand in functional programming.

In my work experiences in Scala, I have witnessed Currying being used (quite effectively) for organizing purposes where it was much clearer that codes are doing some extra filterings in different functions before the actual “ready” content is passed in the main function which is cleaner than writing everything in one place.

For partially applied functions, as the name suggests, it is useful when you aren’t sure what the other value of a function is. If you are adding a + b, say you already know of value a, but b is unknown. then you can partially make up the function which adds a then you can add b when it’s ready later by applying the new function we created earlier which adds a.

Share this post

Me

I am a passionate software developer working in Downtown, Vancouver. I strongly believe in art of algorithms and together with it to write clean and efficient software to build awesome products. If you would like to connect with me, choose one from below options :) You can also send me an email at