Neat Trick for JavaScript Developers to Know 3: Currying, Partial Application, and Partial Application With Placeholders

Neat Trick for JavaScript Developers to Know 3: Currying, Partial Application, and Partial Application With Placeholders

I will discuss what I think are some main points of currying, how and why to use currying to make a partial application, and, in the end, a method I made to make do partial application with placeholders.


Currying is breaking up a function that takes multiple arguments into a sequence of functions that take a single parameter. You can make them manually or create a function that will curry your function. For example, a simple addition function that takes 3 arguments and adds them like:

// Normal function
function sum(x, y, z) {
  return x + y + z;
}

// Curried function:
function curriedSum(x) {
  return function (y) {
    return function (z) {
      return x + y + z;
    }
  }
}        

Or you can also write it in ES6 format like:

const curriedSum = x => y => z => x + y + z;        

When you invoke these curried functions, you use one parameter at a time like:

console.log(curriedSum(1)(4)(8)); // logs 13        

My last article discussed why this works, although it is slightly different. Essentially, when you pass 1 in as an argument, it returns a function that stores 1 as x in its lexical scope. It does the same for 4 but stores 4 as y. Finally, 8 is filled in as z returns the sum of x, y, and z.


Curry has many applications, but I will only mention a few.

Readability: I think it's easier to read once you get used to it.

Error Handling: JavaScript functions don't throw Errors if you give too many or too few arguments. With curry, if you give too many, you will get an error with too little. If you log the return value, you will see a function instead of your expected result unless your expected result is a function, of course.

The DRY principle: We programmers hate repeating ourselves. That's why we have a principal that calls us out on it. Despite that, we do it all the time. Take simply the multiply function where you multiply two numbers:

const multiply = a => b => a * b;        

Typically, if you wanted one specifically for multiplying by 5, you would have to create a whole new function. This is where partial application comes in.

Partial application with curry

a partially applied function is a function that has some arguments already fixed to it, creating a function with fewer parameters. This can be done multiple ways, but if we use our curried multiply function, we can create a partially applied function like:

const multiplyBy5 = multiply(5);
console.log(multiplyBy5(2)); // logs 10
console.log(multiplyBy5(4)) // logs 20        

I read you'll get called out on this immediately, so it's important to differentiate between multiply, a curried function, and multiplyBy5, a partially applied function created from the curry.

Another common use you might see this being used for is to manipulate the Dom like:

const updateElemText = id => content => document.querySelector(`#${id}`).textContent = content;

const updateHeaderText = updateElmText('header');

updateHeaderText('Hey Dave'); 
// Dave was a great help when researching this idea recommended to me to write about https://www.youtube.com/watch?v=I4MebkHvj8g&ab_channel=DaveGray        

To turn your normal boring function into a curried function, all you have to do is understand this monstrosity:

const curry = (fn) =>{
  return curried = (...args) => {
    if (fn.length !== args.length){
      return curried.bind(null, ...args)
    }
    return fn(...args);
  };
}

const sum = (x,y,z) => {
  return x+y+z 
}

const curriedSum = curry(sum);
console.log(curriedSum(10)(20)(30)); //logs 60        

So what's going on here:

curry: returns the function curried with your original function stored in its lexical scope.

...args: The arguments from any past call to curried(which is being stored as curriedSum in the global execution context) and the current invocation.

fn.length: is how many parameters your original function takes since sum has 3 parameters sum.length would equal three.

return curried.bind(null, ...args): I'm ignoring null for now. I would recommend reading more about bind on your own here. What we need to know is that every value after binds first argument is going to be used as arguments the next time you call that function(curried)

return fn(...args): So after args.length is equal to fn.length(3), we pass those args into the original function.

So when we do:

console.log(curriedSum(10)(20)(30)) // logs 60        

  • 10 will be put into an array args; args len is 1, which is not equal to fn.length, so we will return a function with 10 bound to it as a future argument.
  • Invoke the returned func, passing in 20. Now, 10 and 20 are arguments, so they will be stored in the args array, which is still smaller than fn.length. So, return a function, this time with 10 and 20 bound as arguments.
  • Invoke the returned func, passing in 30. Now, 10, 20, and 30 are arguments, and argslength is equal to fn.length now. So we invoke fn (add) passing in the arguments 10, 20, and 30.
  • Finally, add them, return the sum, and log 60 to the console

You may have noticed you can actually pass more than one argument at a time instead of only doing one at a time, but I'm talking about curry here.


Partial Application With Placeholders

My problem is that you must add each parameter in order with all the previous methods. If I am making my burger and map the ingredients out like:

const makeBurger = topBun => lettuce => tomato => ketchup => mustard => cheese => patty => bottomBun => 
return `${topBun},${lettuce ? 'lettuce, ' : ''}...`        

But what if I want a function with the top and bottom bun and patty already filled out? You could simply study the least commonly changed items and build the function with those at the front. Or you could ask why I would have two different types of buns. And to that, I say you're boring.

Anyway, I looked for information on how to do this out of order but couldn't find anything. This gets me thinking, like, why doesn't it work? Then it hit me: Why make a partial function? What about partial arrays? This isn't exactly what I did. Although partial arrays would work, you'll probably see how that idea plays with what I made. Now, I'm probably not the first to do this, but hopefully, I'm the first to show how to do this.

And sike I used a physics equation (not really, but use its values for the example). I'm using a basic equation to calculate the final velocity of an object with a constant acceleration.

Vf = V0 + at

Velocity final = velocity initial + (acceleration * time)

I'm not actually using any math, but what if the initial velocity is often 0 or 100, but everything else is random? Then you might want a function for those. Or you are measuring two different time frames more than others, like 20 seconds, but everything else is random.

So now you want two special functions for initial velocity and one for time, but with the previous methods, you have to add arguments in order so you can only do one or the other.

So my solution is:

function partialFinalVelocity(a, ...b) {
  let i = 0, k = 0;
  console.log(`V1 = ${a[i++] ? a[i-1] : b[k++]}, 
V0 = ${a[i++] ? a[i-1] : b[k++]}, 
a = ${a[i++] ? a[i-1] : b[k++]}, 
t = ${a[i] ? a[i] : b[k]}`);
}

const finalVelocityOver4SecsStarts2Mps = partialFinalVelocity.bind(this, [null, 2, null, 4]);

finalVelocityOver4SecsStarts2Mps(14, 3); 
// logs V1 = 14, V0 = 2, a = 3, t = 4        

What is going on here:

partialFinalVelocity:

function has two parameters, a and b;

a is an array, and b stores any other arguments in an array.

Declare two index variables: i for the a array and k for the b array.

log the string "V1=___, V0=___, a=___, t=___"to the console.

The blanks are filled with ternary statements that all do the same thing:

simultaneously check if a sub i is truthy and immediately after increment i, if truthy then return a sub i - 1 else return b sub k and increment k.

This way, it always checks and increments it in every ternary. If it is null, it will return the current value in b and increment k.

partialFinalVelocity.bind(this, [null, 2, null, 4]): returns a function that will essentially bind the array [null, 2, null, 4] as the first argument in the returned function, so when we invoke the returned function, we only need to pass the (2) arguments it doesn't already have.

It is important to keep in mind that this approach may not be the most readable, and so its practicality on a team may be low. It could also be easily refactored to take more than two arrays, which I might show later.


This has been a dive into Curry, Partial Applications, and Partial Application with Placeholders. Hopefully, I expanded your mind a little bit, and you didn't overload like I did while researching this. There is a lot more you can do with these topics. I probably could have split this into 3 articles, and I definitely didn't cover everything.

If you have any questions or wish to point out any errors, please contact me directly or ask in the comments; thanks!


Helpful sources:

Function.prototype.bind() - JavaScript | MDN (mozilla.org) - read more about the bind method

How to Curry Functions | An Advanced Javascript Tutorial on Currying (youtube.com) - amazing rundown covers some extra topics as well.

Understanding JavaScript currying - LogRocket Blog - covers more use cases

To view or add a comment, sign in

More articles by David Moore

Explore content categories