© Anto Aravinth 2017

Anto Aravinth, Beginning Functional JavaScript, 10.1007/978-1-4842-2656-8_6

6. Currying and Partial Application

Anto Aravinth

(1)Chennai, Tamil Nadu, India

Note

The chapter examples and library source code are in branch chap06. The repo’s URL is: https://github.com/antoaravinth/functional-es6.git

Once checkout the code, please checkout branch chap06:

...

git checkout -b chap06 origin/chap06

...

For running the codes, as before run:

...

npm run playground

...

In this chapter we are going to see what the term currying means. Once we understand what currying does and why it’s useful, we will move to another concept in functional programming called Partial application. Both currying and partial application are important to understand as we will be using them during functional composition!

As seen before in the previous chapters, we are going to look at a sample problem and explain how functional techniques like currying and partial application work.

A Few Terminologies

Before explaining what currying/partial application does, we need to understand a few terminologies that we will be using in this chapter.

unary Function

A function is called unary if it takes a single function argument. For example, function identity is a unary function:

Listing 6-1. unary Identity Function
const identity = (x) => x;

The above function (Listing 6-1) takes only one argument x, so we can call the above function as a unary function.

Binary Function

A function is called binary if it takes two arguments. For example, in Listing 6-2, function add is called a binary function:

Listing 6-2. binary add Function
const add = (x,y) => x + y;

add function takes two arguments x,y; hence we call it a binary function.

And now as you can guess there are ternary functions that take three arguments and so on. But JavaScript does allow a special type of function that we call a variadic function, which takes a variable number of arguments.

variadic Functions

A variadic function is a function that takes a variable number of arguments. Remember that we had arguments in older versions of JavaScript, which we can use to capture the variable number of arguments?

Listing 6-3. variadic Function
function variadic(a){
        console.log(a);
        console.log(arguments)
}

if we call the function variadic like this:

variadic(1,2,3)
=> 1
=> [1,2,3]
Note

As you can see in the output, arguments does capture all the arguments that are passed to a function.

As you can see in the above output (Listing 6-3), using arguments we are able to capture the additional arguments one could call on a function. Using this technique, we used to achieve the variadic functions in ES5 versions. However, starting with ES6, we have a new operator called Spread Operator that we can use to achieve the same result.

Listing 6-4. variadic Function Using Spread Operator
const variadic = (a,...variadic) => {
        console.log(a)
        console.log(variadic)
}

Now if we call the above function we get exactly what we would expect:

variadic(1,2,3)
=> 1
=> [2,3]

As you can see in the result, we were pointed to the first passed argument 1 and all other remaining arguments captured by our variadic variable that uses the ... spread operator! ES6 style is more concise as it clearly mentions that a function does take variadic arguments for processing.

Now that we have some common terminologies in mind with respect to functions, it’s time to turn our attention into the fancy term Currying!

Currying

Have you seen the term Currying n number of times in functional programming blogs and still wonder what it means? Don't worry; we are going to break the Currying definition into smaller n definitions, which will make sense to you!

We’ll start with a simple question: what is Currying? A simple answer to that question would be this:

  • Currying is a process of converting a function with n number of arguments into a nested unary function.

Don’t worry if that doesn’t make sense to you yet! Let’s see what it means by a simple example. Imagine we have a function called add:

const add = (x,y) => x + y;

It’s a simple function. We can call this function like add(1,1), which is going to give me the result 2. Nothing fancy here. Now here is the curried version of the add function:

const addCurried = x => y => x + y;

The above addCurried function is now a curried version of add. If we call addCurried with a single argument:

addCurried(4)

it returns a function where x value is captured via the closure concept as we have seen in the previous chapters:

=> fn = y => 4 + y

So we can call the addCurried function like the following to get the proper result:

addCurried(4)(4)
=> 8

Here we have manually converted add a function, which takes the 2 argument into an addCurried function, which has nested unary functions. Here is how to convert this process into a method called curry (Listing 6-5 ):

Listing 6-5. curry Function Definition
const curry = (binaryFn) => {
  return function (firstArg) {
    return function (secondArg) {
      return binaryFn(firstArg, secondArg);
    };
  };
};
Note

I have written the curry function in ES5 format, as I want the reader to visualize the process of returning a nested unary function.

Now we can use our curry function to convert our add function to a curried version like this:

let autoCurriedAdd = curry(add)
autoCurriedAdd(2)(2)
=> 4

The output is exactly what we wanted to get! Now it’s time to revise the definition of Currying:

  • Currying is a process of converting a function with n number of arguments into a nested unary function.

As you can see in our curry function definition, we are converting the binary function into nested functions, each of which takes only one argument; that is, we are returning the nested unary functions! Hopefully I have clarified the term currying in your head. But the obvious questions you still have are these: Why do we need currying? What is its use?

Currying Use Cases

To begin with, we’ll start simple. Imagine we have to create a function for creating tables. For example, we need to create tableOf2, tableOf3, tableOf4 and so on.

We can achieve the same via the following in Listing 6-6:

Listing 6-6. tables Function without Currying
const tableOf2 = (y) => 2 * y
const tableOf3 = (y) => 3 * y
const tableOf4 = (y) => 4 * y

with that in place, the functions can be called this:

tableOf2(4)
=> 8
tableOf3(4)
=> 12
tableOf4(4)
=> 16

Now you see that you can generalize the tables concept into a single function like this:

const genericTable = (x,y) => x * y

and then you can use genericTable to get tableOf2 like the following:

genericTable(2,2)
genericTable(2,3)
genericTable(2,4)

and the same for tableOf3 and tableOf4. But if you notice the pattern, we are filling up 2 in the first argument for tableOf2, 3 for tableOf3, and so on! Perhaps you are thinking that we can solve this problem via curry? Let’s build tables from genericTable using curry:

Listing 6-7. tables Function Using Currying
const tableOf2 = curry(genericTable)(2)
const tableOf3 = curry(genericTable)(3)
const tableOf4 = curry(genericTable)(4)

now you can do your testing with these curried version of tables:

console.log("Tables via currying")
console.log("2 * 2 =",tableOf2(2))
console.log("2 * 3 =",tableOf2(3))
console.log("2 * 4 =",tableOf2(4))


console.log("3 * 2 =",tableOf3(2))
console.log("3 * 3 =",tableOf3(3))
console.log("3 * 4 =",tableOf3(4))


console.log("4 * 2 =",tableOf4(2))
console.log("4 * 3 =",tableOf4(3))
console.log("4 * 4 =",tableOf4(4))

which is going to print the value we expect:

Table via currying
2 * 2 = 4
2 * 3 = 6
2 * 4 = 8
3 * 2 = 6
3 * 3 = 9
3 * 4 = 12
4 * 2 = 8
4 * 3 = 12
4 * 4 = 16

A logger Function - Using Currying

The previous section example helped you to understand what currying does. But let’s use a bit more complicated example in this section. As developers when we write code, we do a lot of logging at several stages of the application. We could write a helper logger function that looks like the following (Listing 6-8):

Listing 6-8. Simple loggerHelper Function
const loggerHelper = (mode,initialMessage,errorMessage,lineNo) => {
        if(mode === "DEBUG")
                console.debug(initialMessage,errorMessage + "at line: " + lineNo)
        else if(mode === "ERROR")
                console.error(initialMessage,errorMessage + "at line: " + lineNo)
        else if(mode === "WARN")
                console.warn(initialMessage,errorMessage + "at line: " + lineNo)
        else
                throw "Wrong mode"
}

and when any developer from our team needs to print an error to the console from Stats.js file, he/she can use the function like the following:

loggerHelper("ERROR","Error At Stats.js","Invalid argument passed",23)
loggerHelper("ERROR","Error At Stats.js","undefined argument",223)
loggerHelper("ERROR","Error At Stats.js","curry function is not defined",3)
loggerHelper("ERROR","Error At Stats.js","slice is not defined",31)

and similarly we can use the ‘loggerHelper’ function for debug and warn messages. As you can tell, we are repeating the arguments mainly mode and initialMessage for all the calls. Can we do it better? Yes, we can do the above calls better via currying. Can we use our curry function that is defined in the previous section? Unfortunately no; the reason is the curry function that we have designed can handle only the binary functions, not a function like loggerHelper that takes 4 arguments.

Let us solve this problem and implement the fully functional curry function, which handles any function with n number of arguments.

Revisit Curry

We all know that we can curry (Listing 6-5 ) only a function. How about many functions? It’s simple but important to have it in our implementation of curry. Let’s add the rule first:

Listing 6-9. Revisting curry Function Definition
let curry =(fn) => {
    if(typeof fn!=='function'){
        throw Error('No function provided');
    }
};

With that check in place, if others call our curry function with an integer like 2, etc., they get back the error! That’s perfect! The next requirement to our curried function is that if anyone provided all arguments to a curried function, we need to execute the real function by passing the arguments. Let’s add that (Listing 6-10):

Listing 6-10. curry Function Handling Arguments
let curry =(fn) => {
    if(typeof fn!=='function'){
        throw Error('No function provided');
    }


    return function curriedFn(...args){
      return fn.apply(null, args);
    };
};

Now if we have function called multiply:

const multiply = (x,y,z) => x * y * z;

we can use our new curry function like the following:

curry(multiply)(1,2,3)
=> 6
curry(multiply)(1,2,0)
=> 0

So let’s look at how it really works; we have added the logic in our curry function like this:

return function curriedFn(...args){
        return fn.apply(null, args);
};

The returned function is a variadic function, which returns the function result by calling the function via apply along by passing the args:

. . .
fn.apply(null, args);
. . .

With our curry(multiply)(1,2,3) example, args will be pointing to [1,2,3] and since we are calling apply on fn, it’s equivalent to:

multiply(1,2,3)

which is exactly what we wanted! Thus we get back the expected result from the function.

Now let us get back to the problem of converting the n argument function into a nested unary function (that’s the definition of curry itself)!

Listing 6-11. curry Function Converting n arg Function to unary Function
let curry =(fn) => {
    if(typeof fn!=='function'){
        throw Error('No function provided');
    }


    return function curriedFn(...args){

      if(args.length < fn.length){
        return function(){
          return curriedFn.apply(null, args.concat( [].slice.call(arguments) ));
        };
      }


      return fn.apply(null, args);
    };
};

We have added the part:

if(args.length < fn.length){
        return function(){
          return curriedFn.apply(null, args.concat( [].slice.call(arguments) ));
        };
}

Let’s understand what’s happening in this piece of code, one by one:

args.length < fn.length

This particular line checks if the argument that is passed via ...args length and the function argument list length is less or not. If so we go into the if block, or else we fall back to call the full function as before.

Once we enter the if block, we used the apply function to call the curriedFn recursively like this:

curriedFn.apply(null, args.concat( [].slice.call(arguments) ));

The snippet:

args.concat( [].slice.call(arguments) )

is important. Using the concat function, we are concating the arguments that are passed one at a time and calling the curriedFn recursively. Since we are combining all the passed arguments and calling it recursively, we will meet a point in which the line:

 if (args.length < fn.length)

condition fails. As the argument list length (‘args’) and function argument length (fn.length) will be equal, thus skipping the if block and calling up:

return fn.apply(null, args);

which is going to yield the functions’ full result!

With that understanding in place, we can use our curry function to invoke the multiply function:

curry(multiply)(3)(2)(1)
=> 6

Perfect! We have created our own curry function.

Note

You can call the above code snippet like the following, too:

let curriedMul3 = curry(multiply)(3)
let curriedMul2 = curriedMul3(2)
let curriedMul1 = curriedMul2(1)

where curriedMul1 will be equal to 6. But we do it like curry(multiply)(3)(2)(1) as it is much more readable!

An important point to note is that our curry function is now converting a function of n arguments into a function that can be called as a unary function as the example shows.

Back to logger Function

Now let’s solve our logger function using the defined curry function. Bringing up the function here for easy reference (Listing 6-8):

const loggerHelper = (mode,initialMessage,errorMessage,lineNo) => {
        if(mode === "DEBUG")
                console.debug(initialMessage,errorMessage + "at line: " + lineNo)
        else if(mode === "ERROR")
                console.error(initialMessage,errorMessage + "at line: " + lineNo)
        else if(mode === "WARN")
                console.warn(initialMessage,errorMessage + "at line: " + lineNo)
        else
                throw "Wrong mode"
}

The developer used to call the function:

loggerHelper("ERROR","Error At Stats.js","Invalid argument passed",23)

Now let’s solve the repeating first two arguments problem via curry:

let errorLogger = curry(loggerHelper)("ERROR")("Error At Stats.js");
let debugLogger = curry(loggerHelper)("DEBUG")("Debug At Stats.js");
let warnLogger = curry(loggerHelper)("WARN")("Warn At Stats.js");

Now we can easily refer to the above curried functions and use them under the respective context:

//for error
errorLogger("Error message",21)
=> Error At Stats.js Error messageat line: 21


//for debug
debugLogger("Debug message",233)
=> Debug At Stats.js Debug messageat line: 233


//for warn
warnLogger("Warn message",34)
=> Warn At Stats.js Warn messageat line: 34

That’s brilliant! We have seen how curry function helps in the real world to remove a lot of boilerplates in function calls! Don't forget to say thanks to the closures concept, which is backing up the curry function.

Currying in Action

In the previous section we created our own ‘curry’ function. We have also seen a simple example of using the ‘curry’ function.

In this section we are going to see small but compact examples where the currying technique will be used. The examples shown in this section will make you better understand how to use currying in your day-to-day activities.

Finding number in Array Contents

Imagine we want to find the array content that has a number. We can solve the problem via the following code snippet:

let match = curry(function(expr, str) {
  return str.match(expr);
});

The returned match function is a curried function. We can give the first argument expr a regular expression /[0-9]+/ that will indicate whether the content has a number in it.

let hasNumber = match(/[0-9]+/)

Now we will create a curried filter function:

let filter = curry(function(f, ary) {
  return ary.filter(f);
});

Now with hasNumber and filter in place, we can create a new function called findNumbersInArray:

let findNumbersInArray = filter(hasNumber)

Now you can test it:

findNumbersInArray(["js","number1"])
=> ["number1"]

That’s great!

squaring an Array

We know how to square contents of an array. We have also seen the same problem in previous chapters. We use map function and pass on square function to achieve the solution to our problem. But here we can use the curry function to solve the same problem in another way:

let map = curry(function(f, ary) {
  return ary.map(f);
});


let squareAll = map((x) => x * x)

squareAll([1,2,3])
=> [1,4,9]

As you can see in the above example, we have created a new function squareAll that we can now use elsewhere in our code base! Similarly you can also do this for findEvenOfArray, findPrimeOfArray, etc.

Data Flow

In both sections of using currying, we have designed the curried functions such that it always takes the array at the end. This is intentional way of creating a curried function! As talked about in previous chapters, we as programmers often work on data structures like array, so making the array as the last argument allows us to create lot of reusable functions like squareAll and findNumbersInArray that we can use throughout the code base!

Note

In our source code companion, we have termed the curry function as curryN. It’s just to keep the old curry remains as is, which was supposed to do currying on binary functions!

Partial Application

In this section we are going to see yet another function called partial that allows developers to apply the function arguments partially!

Imagine we want to do a set of operations after every 10 ms. Using the setTimeout function, we can do this:

setTimeout(() => console.log("Do X task"),10);
setTimeout(() => console.log("Do Y task"),10);

As you can see, we are passing on 10 for every one of our setTimeout function calls. Can we hide that from the code? Can we use curry function to solve this problem? The answer is no. The reason is that the curry function applies the argument from the leftmost to rightmost lists! Since we want to pass on the functions as needed and keep 10 as a constant (which is most of the argument list), we can't use curry as such. One workaround is that we can wrap our setTimeout function so that the function argument becomes the rightmost one:

const setTimeoutWrapper = (time,fn) => {
  setTimeout(fn,time);
}

Then we can use our curry function to wrap our setTimeout to a 10-second delay:

const delayTenMs = curry(setTimeoutWrapper)(10)
delayTenMs(() => console.log("Do X task"))
delayTenMs(() => console.log("Do Y task"))

which will work as we needed it to. But the problem is we have to create wrappers like setTimeoutWrapper, which will be an overhead! And that’s where we can use partial application techniques!

Implementing partial Function

In order to fully understand how the partial application technique is working, we will be creating our own ‘partial’ function in this section. Once the implementation is done, we will learn how to use our ‘partial’ function with a simple example.

The implementation of partial function looks like the following (Listing 6-12):

Listing 6-12. partial Function Definition
const partial = function (fn,...partialArgs){
  let args = partialArgs;
  return function(...fullArguments) {
    let arg = 0;
    for (let i = 0; i < args.length && arg < fullArguments.length; i++) {
      if (args[i] === undefined) {
        args[i] = fullArguments[arg++];
        }
      }
      return fn.apply(null, args);
  };
};

Let’s quickly use the partial function with our current problem:

let delayTenMs = partial(setTimeout,undefined,10);
delayTenMs(() => console.log("Do Y task"))

which will print to the console as you expect. Now let’s walk through the implementation details of partial function. Using closures, we are capturing the arguments that are passed onto the function for the first time:

partial(setTimeout,undefined,10)

//will lead to
let args = partialArgs
=> args = [undefined,10]

And we return a function that will remember the args value (yeah, again we are using closures!). The returned function is super easy. It takes an argument called fullArguments. So we call functions like delayTenMs by passing the argument:

delayTenMs(() => console.log("Do Y task"))

//fullArguments points to
//[() => console.log("Do Y task")]


//args using closures will have
//args = [undefined,10]

Now in the for loop we iterate and create the necessary arguments array for our function:

if (args[i] === undefined) {
      args[i] = fullArguments[arg++];
  }
}

Now let’s start with value i as 0:

//args = [undefined,10]
//fullArguments = [() => console.log("Do Y task")]
args[0] => undefined === undefined //true


//inside if loop
args[0] = fullArguments[0]
=> args[0] = () => console.log("Do Y task")


//thus args will become
=> [() => console.log("Do Y task"),10]

As you can see in the above code snippet examples, our args point to the array as we would expect for setTimeout function calls. Once we have the necessary arguments in args, we call the function via fn.apply(null, args)!

Remember that we can apply partial for any function that has n arguments. To make the point concrete, let’s look at an example. In JavaScript we use the following function call to do JSON pretty print:

let obj = {foo: "bar", bar: "foo"}
JSON.stringify(obj, null, 2);

As you can see, the last two arguments for the function call stringify are always going to be the same null,2. We can use partial to remove the boilerplate:

let prettyPrintJson = partial(JSON.stringify,undefined,null,2)

and then you can use prettyPrintJson to print the json:

prettyPrintJson({foo: "bar", bar: "foo"})

which will give you the output:

"{
  "foo": "bar",
  "bar": "foo"
}"
Note

There is a slight bug in our implementation of partial function. What if you call prettyPrintJson again with a different argument? Does it work?

It always gives the result for the first invoked argument, but why? Can you see where we are making the mistake?

HINT: Remember, we are modifying the partialArgs by replacing the undefined values with our argument, and Arrays are used for reference!

Currying vs. Partial Application

We have seen both of these techniques. So the question is when to use which one? The answer depends on how your API is been defined. If your API is defined as such map,filter then we can easily use the curry function to solve our problem. But as discussed in the previous section, life is not always easy. There could be functions that are not designed for curry such as setTimeout in our examples. In those cases, the best fit option would be to use partial functions! After all, we use curry or partial to make function arguments/ function setup easy and more powerful!

And also it’s important to note that currying will return nested unary functions; we have implemented curry so that it takes n arguments just for our convenience. And also it’s a proven fact that developers need either curry or partial but not both.

And that brings us to the end of our discussion!

Summary

Currying and partial application are always a tool in functional programming. We started the chapter by explaining the definition of currying, which is nothing but converting a function of n arguments into nested unary functions. We saw the examples of currying and where it can be very useful. But there are cases where you want to fill the first 2 arguments of a function and the last argument, leaving the middle argument to be unknown for a certain time! And that’s where partial application comes into the picture. In order to fully understand both these concepts, we have implemented our own curry and partial functions! We have made a lot of progress, we’re not done yet!

Functional programming is all about composing functions – composing several small functions to build a new function! Composing and Pipelines will be the topic of the next chapter. Stay tuned!