Perpetual Currying in JavaScript

Param Singh
codeburst
Published in
8 min readJan 18, 2019

--

Vatican Museum Stairs

One of the best characteristics of JavaScript is it being a Functional Programming Languages which opens up pathways to some of the coolest programming patterns. One of them is Currying. As cool as it sounds and behaves, it could be mind boggling to understand in the first go. In this article, I’ll try to explain what currying is in simple language and how you can extend it further to fit your needs.

Currying

Currying is about decomposing a function taking multiple arguments into numerous functions with single arguments.

The definition holds true for primitive Currying. Later, in this article we’ll see some more advance patterns with Currying.

Let me explain more through an easy example. Say you have a function multiply as

const multiply = ( a, b ) => a * b;

Now, the way you invoke a function like this would be

multiply(2, 3)

But, with currying it’ll be broken down into multiple functions based on the arity(Number of arguments) of the given function, which is 2 in this case. It’ll look like this

const mul = curry(multiply);
mul(2)(3);

Also, if the name sounds a little bizarre to you, it’s named after Haskell Curry, who worked on the mathematical foundations of functional programming.

Agenda

Post reading this article, you’ll be able to:

  • Understand what currying is.
  • Build a utility function for transforming a function to it’s curried version as we saw above. mul(2)(3)(4)
  • Understand Variadic Currying i.e mul(2,3)(4) or mul(2)(3,4)
  • Build Infinite Currying function i.e currying a function without knowing its arity. Eg: mul(2)(3)(4)....(8)()
  • Incorporating Variadic Currying pattern in our Infinite Currying utility. Eg: mul(2)(3,4,5)(6)(7,8)()

Implementing Currying

Let’s see how we can build a specific curry function for multiply function that takes three arguments

Here are three functions returned simultaneously from inside the parent function. The first two functions with args x and y are acting as accumulator functions and storing it in the scope chain of the inner functions or as we can precisely call them as closures in JavaScript. Here’s a lucid definition of closures

A closure is an inner function that has access to the outer (enclosing) function’s variables — scope chain. The closure has three scope chains: it has access to its own scope (variables defined between its curly brackets), it has access to the outer function’s variables, and it has access to the global variables.

What this means is, the second function with argument y has access to the variable x from it’s parent function. Same way, the third function with argument z has access to both x & y variables since they get linked to the scope of that function and the function body of third inner function can lookup or traverse back through this hierarchical chain of scope bindings when it encounters a variable that’s not defined in the current function body viz x & y in this case.

Building a curry utility function

Consider the following function with three arguments.

const mul = ( a, b, c ) => a * b * c;

Our purpose is to create a wrapper function which takes this mul function as a parameter and returns a curried version of it so that it can be called in the form of _mul(1)(2)(3) . Remember that we won’t be mutating the original mul function, rather returning a new function as _mul in this case.

_mul = curry(mul);

Moving forward, let’s try to generalise what we did in the implementing currying section. What we need to determine is the number of arguments of the function aka arity and build a recursive set of functions the same number of times.

In JS, number of arguments or arity of a function can be determined by using the length property of the given function as

N = mul.length; //3

Now that we are able to dynamically find the arity of the function, we can form a logic to recursively return inner functions N number of times.

Let me go over a detailed explanation as follows since this is the heart of curry pattern implementation.

Firstly, we’re creating two functions we want to curry as _sum3 with 3 arguments and _sum4 with 4 arguments.

Next, in our curry function, we take function as fn as an input to be curried. We find the arity of it using fn.length getter on it and store it in N.

Now, the main thing, we want to return inner function N times, i.e the number of times the curried method of sum would be called is equal to the number of argument it takes as _sum(1,2,3,...,N) => sum(1)(2)(3)...(N)

So, we create a function as innerFn that keeps track of the N variable based on which it determines whether to return another function or terminate the process by invoking the actual function with all the accumulated arguments. Hence, it’s also called as an Accumulator function since it accumulates all the individual arguments being passed to the curried function one by one, by pushing it into the accumulated array as [...args, a] and eventually calls the original function.

Let’s understand with an example. Initially, for sum3, N = 3 for which we execute and return the 'outcome’ of innerFn which is the inner function on line 8 as actualInnerFn. It’s nothing but another function which takes a single argument. Inside it’s body, it checks whether to repeat the whole process further or terminate. This is the actual function that is called by the user eventually one by one as sum(1)(2)(3)

When it executes for n = 3 we check whether it’s the last argument to be called. But it’s not, we need two more iterations which return our actualInnerFn (3 - 1 = 2) times.

The same is repeated for n = 2 which again returns the actualInnerFn with single argument which in turns again calls our accumulator innerFn with n = 1 This time, again the actualInnerFn is returned but we have to terminate the recursion here.

This is the base case that when n = 1 which indicates it’s the last function to be returned. Hence, inside the body, we’ve written the termination case by identifying the condition and executing the original function with the arguments accumulated so far in the args variable and the last argument passed as a as fn(...args, a)

This is all about it. Hope, it’s clear with the explanation above.

Variadic Currying

Taking it a step further, let’s try to achieve something like calling sum(2,3)(4) or sum(2)(3,4) and still getting the same results. This is called Variadic Currying since, we’re able to use varargs or variable number of arguments in the function being called recursively.

To be precise, we’re allowing our actualInnerFn to have variable number of arguments instead of a single argument.

In addition to making our actualInnerFn accept variable arguments, we need to change the termination case logic as well. Eg: if the function is called this as sum(1)(2,3) We need to take into account the length is arguments of 2 and 3 since the individual calls for (2) and (3) are clubbed together. Hence, we need to call the original function is the number of arguments N is reached.

This is how the final implementation looks like

Cool, we’re able to implement variable arguments in it. But can we do better?

Infinite Currying

The problem that I see with what we’ve achieved so far is that we have to defined a function everytime we need it for a different arity i.e For 3 arguments I have to define sum3 function, for 4 arguments, I need to defined sum4 function.

Is there a way we could think of, where in we pass the general intent or operation of the function like addition, multiplication, concatenation for two arguments as (x, y) => x + y and then apply it to N number of arguments. Now, there’s an issue with this, which is we need N in order to handle our termination case or else the code with continue to return innerFn recursively which may lead to stack overflow.

sum(2)(3)(4)......

Hence, we need to identify through some way that now we’re done with our number of arguments and all we would like is the output of that operation we passed. How about having a function invocation with empty arguments like?

sum(2)(3)(4)(5)() // 14

There could be a number of ways, all we need is to signal somehow to the actualInnerFn that we’d like to stop and get the result now.

Something like passing a sentinel as sum(2)(3)(4)('STOP') and we can apply a check inside the actualInnerFn as if(a === 'STOP')

There are some changes which I’d like to explain here.

  • We don’t need to pass the length of the arguments as N here since we don’t have it.
  • The user can invoke the curried function arbitrary number of times, hence, we don’t have any count as N to predict.
  • We need to accumulate the arguments the same way as earlier in args variable
  • The base case or termination case inside our actualInnerFn checks whether there any arguments passed to it. If not, it process all the accumulated arguments.
  • Since, we don’t have a function prepared for the unknown arity say M at that time, we can’t pass the arguments at once to a function simply like we did in case with our sum3 or sum4 functions.
  • All we have is a function defining operation of the function to be curried as (x, y) => x + y
  • Given this scenario, reduce method of JS array can be very helpful here, since we need to loop over all the accumulated values and call the operation on them iteratively while storing them in an accumulator variable
args.reduce((accumulator, a) => {
return fn(accumulator, a)
}, 0);
  • But we need to pass a seed value to start with, since we’re dealing with summation, 0 can be passed initially since adding it with any value given the result of that value. In case of multiplication, we can pass 1. For concatenation, we may pass empty string ''
  • We’ll try to abstract this seed value out from our implementation in our next section

Infinite Variadic Currying

Let’s try to bring varargs into our infinite currying implementation so far.

What I’m doing here is processing a chunk or arguments on the fly like evaluating (5, 6) before they’re passed to the next iteration. You’re free to implement by aggregating all the args and computing them at once in the reduce function.

Also, for the sake of generalisation, I’m supplying the curry method and seedValue param for our reduce method.

That’s all folks.

Summary

We learnt about a cool functional programming pattern and how to implement it by creating a wrapper/utility method called as curry(fn) that takes a function as an input and allow us to call the function in number of steps recursively. We also extended our implementation to Variadic Currying which allows us to pass multiple arguments into the function calls. Later, we implemented a way where we can just specify the operation we want to do on a set of data and call it infinite or rather a finite but unpredictable number of times and finally incorporated variadic arguments into it.

Feel free to fork this pen and tinker around with it by extending or augmenting it to fit your needs and let me know anything you discovered in the comments below.

Thanks :)

--

--

Senior Front-end Engineer at AWS, Ex-Revolut, Flipkart. JS enthusiast. Cynophile. Environmentalist