Currying is a process in functional programming in which we can transform a function with multiple arguments into a sequence of nesting functions. It returns a new function that expects the next argument inline.
NB:The number of arguments a function takes is also called arity
.
For example,
function multiply(a, b) {
// do sth
}
function _multiply(a, b, c) {
// do sth
}
function multiply
takes two arguments (2-arity function) and _multiply
takes three arguments (3-arity function).
So,Currying break down a function that takes multiple arguments into a series of functions that each take only one argument.
Here's an example in JavaScript:
function multiply(x,y,z) {
return x*y*z;
}
This is a function that takes three arguments, x, y and z and returns their product.
multiply(1,2,3); // 6
We will now curry this function:
function multiply(x) {
return (y) => {
return (z) => {
return x * y * z
}
}
}
console.log(multiply(1)(2)(3)) // 6
Now,we turn a function call multipy(1,2,3) into multipy(1)(2)(3)
To better understand this multiply(1)(2)(3), we may divide it into three parts:
const multi1 = multiply(1);
const multi2 = multi1(2);
const result = multi2(3);
console.log(result); // 6
Now,let's get to know how it works.We passed 1 to the multiply function:
let multi1 = multiply(1);
It returns the function:
return (y) => {
return (z) => {
return x * y * z
}
}
Now, multi1
holds the above function definition which takes an argument y
.
We called the multi1
function, passing in 2
:
let multi2 = multi1(2);
The multi1 will return the third function:
return (z) => {
return x * y * z
}
The returned function is now stored in multi2 variable.
multi2 will essentially be:
multi2 = (z) => {
return x * y * z
}
When multi2 is called with 3 as the parameter,
const result = multi2(3);
It does the computation using the parameters that were previously provided in: x = 1, y = 2, and returns 6.
console.log(result); // 6
The last function only accepts z
variable but will perform the operation with other variables whose enclosing function scope has long since returned. Because of Closure
, it still functions🔥.
Currying & Partial application 🤔
Some may now believe that the number of nested functions a curried function has is proportional to the number of arguments it receives. That qualifies it as a curry.
Let's take same multiply example:
function multiply(x) {
return (y) => {
return (z) => {
return x * y * z
}
}
}
It can be called like this:
let a = multiply(10);
a(3,12);
a(20,12);
a(20,13);
// OR
multiply(10)(3,12);
multiply(10)(20,12);
multiply(10)(20,13);
In contrast to our previous version, which had three arguments and three nesting functions, the above function takes three arguments and contains two nested functions.
This isn't a curry in the traditional sense. We've only used the multiply function in a limited way.
Currying and Partial Application are related (because of closure), but they are of different concepts.
Partial application transforms a function into another function with smaller arity
.
function multiply1(x, y, z) {
return multiply2(x,y,z)
}
// to
function multiply1(x) {
return (y,z) => {
return mulitply2(x,y,z)
}
}
For Currying, it would be like this:
function multiply1(x) {
return (y) = > {
return (z) = > {
return multiply2(x,y,z)
}
}
}
Currying generates nested functions based on the number of arguments passed into the function. Each function is given a parameter. There is no currying if there is no argument.
To create a function that accepts a function and returns a curried function, follow these steps:
function currying(fn, ...args) {
return (..._arg) => {
return fn(...args, ..._arg);
}
}
The above function takes a function (fn) and a variable number of parameters (...args) to curry. After fn, the rest operator is used to collect the number of parameters into...args.
Then, as... args, we return a function that additionally collects the remaining parameters. This function uses the spread operator to call the original function fn, giving in...args and... args as parameters, and then returns the value to the user.
The above code may now be used to build a curry function.
function multiply(x,y,z) {
return x * y * z
}
let multi = currying(multiply,10);
multi(2,3); // 60
multi(1,4); // 40
Closure
makes currying possible in JavaScript. I hope you have learned something new about currying!
If you've reached this point, thank you very much. I hope that this tutorial has been helpful for you and I'll see you all in the next.
If you like my work, please consider
so that I can bring more projects, more articles for you
If you want to learn more about Web Development don't forget to to follow me on Youtube!
Top comments (14)
Nice article, but you seem to have a somewhat wrong idea of what currying is, and are conflating it with partial application. To clarify:
Partial application
A function is called with less arguments than it needs, and returns a new function that takes the remaining arguments. Some languages support this out of the box:
And some, like JS, can only approximate this behaviour using higher-order functions:
Currying
On the other hand, currying is the process of taking any function and converting it into a series of nested functions of arity 1:
This can sometimes be done automatically, but only in languages that offer some mechanism to inspect a functions arity, and generate a new (nested) function until the right number of arguments has been provided.
Just for fun, here's an automatic currying function:
For your above definition of currying how can you say just one arity ? the last function can have any arity. Also, bellow matches to your definition of partial as well.
const add = a => (b, c) => a + b + c
add(1)(2,3)
The practical answer is that currying makes creating anonymous functions much easier. Even with a minimal lambda syntax, it's something of a win; compare:
map (add 1) [1..10]
map (\ x -> add 1 x) [1..10]
If you have an ugly lambda syntax, it's even worse. (I'm looking at you, JavaScript, Scheme and Python.)
net-informations.com/js/iq/default...
I honestly don't think JS has such a bad lambda syntax;
[1,2,3].map(x => 1+x)
is still quite acceptable compared to what we have in Lua:function(x) return 1+x end
** keep in mind that Lua is intentionally minimalistic, making it an easy transpilation target for languages with more convenient syntax, so this is effectively not a big problem
Just to be honest, I got scared of things like that:
const mul = x => y => x*y
This is something readable, but some people can enjoy this "non-hability" of creating variable names, that is the worse thing you can do, but the action of refactoring to become faster, I totally agree, but needs to be well written, and naming is important (even for a an internet example).
It's all OK to explain what currying is, but without an explanation as to why one would want to go to all this trouble and extra complexity is necessary to support the article.
Thanks, it would be really cool to know if there's some real world case where this is a solution.
I often use it when I want to use a function in array.map but it takes more than one argument. Supply the initial argument(s) then use the returned function in map.
That makes a bunch of sense, thanks!
It's just pure vanilla JavaScript. Fundamental principle of functional programming so any language that treats functions as arguments can do this - not a JavaScript mess 😉
Interesting article. Never heard of that. But what about the browser support? And from which EcmaScript is it being supported?
hi, nice article.
can you please also provide some use case for more clarification.
This thing is a pure brain fck for Java devs, like me. Rest, please keep unveiling secrets of this js.
AHH ! The JavaScript mess.....