Refactor a Function to Use Currying in JavaScript

Kyle Shevlin
InstructorKyle Shevlin

Share this video with your friends

Send Tweet
Published 3 years ago
Updated 3 years ago

This lesson teaches you what currying is: the act of refactoring a function so that it receives its arguments one at a time. We will use the canonical example of an add function to demonstrate this. This lesson also teaches the concept of “arity”, the number of arguments a function receives, as it is useful knowledge for functional programming.

Instructor: [00:00] currying is the act of taking a function that normally receives more than one argument such as add and refactoring it so that it becomes a higher-order function that returns a series of functions each accepting only one argument and only evaluating once we receive our final argument.

[00:18] If I try using add function the normal way by passing both variables in at the same time, and I log that out, all I'll get back is a function. This happens because the second variable is ignored and we receive back the function that's been returned on line four.

[00:35] Instead, I can save the return function as a new variable. In this case, we'll call it add 3. I can now take our new function and give it its final argument. I can reuse this function. I'll call it several times with different numbers. If I log this out, I get the correct summation. Every function and functional programming is curried like this.

[00:58] We can write our curried functions much more succinctly using an ES2015 arrow function. Arrow functions implicitly return each expression that comes after an arrow. In this case, we return this full function after receiving our X. After receiving our Y, we return the evaluation of X+Y.

[01:17] At this point, I want to briefly discuss some jargon. That is the word arity. Arity describes the number of arguments a function receives. Depending on the number it receives, there are specific words to describe these functions.

[01:31] A function that receives one is called a unary function. A function that receives two arguments is called a binary, three equals a ternary, and four equals a quaternary, so forth and so on. Thus the act of currying can be described as taking a multivariate function and turning it into a series of unary functions.

Tony Catalfo
Tony Catalfo
~ 3 years ago

Would we use add2 like this add2(3)(4)?

Tony Catalfo
Tony Catalfo
~ 3 years ago

Would we use add2 like this add2(3)(4)?

Kyle Shevlin
Kyle Shevlininstructor
~ 3 years ago

Hi Tony,

That is correct. If you had both arguments to pass in at the same time, you would need to pass them that way. In your particular example, add2(3) returns a function. This is a partially applied function that has the argument 3 stored in closure. Because this is a function, we need to call it with the second argument, 4, in order to invoke it and have the function return the summation. To break it down into steps, it looks like this:

const add = x => y => x + y
const addWithThree = add(3) // Returns a function that looks like `y => 3 + y`
console.log(addWithThree(4)) // 7, because 4 => 3 + 4
console.log(addWithThree(10)) // 13, because 10 => 3 + 10
Carlos
Carlos
~ 3 years ago

"4 = a qaternary, so fourth and so on." I see what you did there.

Maciej Kołodziejczak
Maciej Kołodziejczak
~ 2 years ago

Can you provide any use cases this may be actually useful? Add function isn't a good one or I just don't see it.

Kyle Shevlin
Kyle Shevlininstructor
~ 2 years ago

Maciej, please watch the next lesson on partial application. You're correct that add doesn't seem like a powerful example, but it's the canonical way of teaching the concept. The goal of this lesson is to simply understand that you don't need to receive all your arguments at once, but can receive them in series. This will open up new possibilities such as partial application and functional composition that you cannot get without currying.

Let's take for example writing a map function that takes a function to call for each iteration and an array of items.

const map = callback => array => array.map(callback)

Now, because we've curried that function, we can accomplish something we otherwise would not be able to do. We can supply the first argument, callback and get back a function that can be used on any array.

const getSquares = map(number => number * number)

const arr1 = [1, 2, 3]
const arr2 = [4, 5, 6]

console.log(getSquares(arr1)) // [1, 4, 9]
console.log(getSquares(arr2)) // [16, 25, 36]

Already we gain the ability to pipe data into a function and get output out, and we never have to declare the callback again. There are many applications of currying, but finishing the rest of the course should help demonstrate some of their benefits.