## DEV Community

TusharShahi

Posted on • Updated on

# Polyfill: Create your own curry()

Saw this question in an interview some time ago:

Create a method curry that when passed in a function, will return a curried version of the function:

``````const join = (a,b,c) => {
return `\${a}_\${b}_\${c}`
}

const curriedJoin = curry(join);

console.log(curriedJoin(1)(2,3)); //1_2_3
console.log(curriedJoin(1,2)(3)); //1_2_3
console.log(curriedJoin(1)(2)()()(3)); //1_2_3
console.log(curriedJoin(1,2,3)); //1_2_3

``````

## What is currying?

Wikipedia says:

In mathematics and computer science, currying is the technique of converting a function that takes multiple arguments into a sequence of functions that each takes a single argument.

A function that takes multiple arguments is transformed into a series of functions that take single arguments.

## Initial approach

Based on the definition this is how the function is supposed to be structured:

``````const curry = (fn) => {

const curriedFunction = (...args) => {

};
return curriedFunction;
};
``````

The function takes an argument function `fn` and returns a new function.
The returned function expects arguments, and for ease of handling `...args` (Rest Operator) is used. It is a way to handle indefinite number of arguments. Now `args` is an array having all the function arguments.

## Returning a function

Every time the curried function is called, a function has to be returned. It is also necessary to keep track of the arguments passed at every step of the sequence. When we want to execute the function, we can call `fn` with `...args`.

``````const curry = (fn) => {

const curried = (...args) => {
let arr = [];
arr = [...arr,...args];
const innerFunc = (...innerArgs) => {
arr =[...arr,...innerArgs];
if(arr.length === fn.length){
return fn(...arr);
}
else{
return innerFunc;
}

};
return innerFunc;
}
return curried;
};
``````

`fn.length` returns the number of parameters expected by `fn`. A javascript function can take as many arguments as passed, but this value will always return the number of formal parameters.

It is useful in the base condition. As soon as the length of the array is equal to the number of parameters expected, the callback function can be called.

## Edge conditions

The above solutions solve most of the cases except this:

``````console.log(curriedJoin(1,2,3));
``````

To handle this, the function should have another check in case all the arguments are passed in the first go itself.

``````const curry = (fn) => {

const curried = (...args) => {
let arr = [];
if(args.length === fn.length){
return fn(...args);
}
else{
arr = [...arr,...args];
const innerFunc = (...innerArgs) => {
arr =[...arr,...innerArgs];
if(arr.length === fn.length){
return fn(...arr);
}
else{
return innerFunc;
}

};
return innerFunc;
}
}
return curried;
}
``````

## Summary

The question tests the solver's understanding of closures. It also relies on the fact that the solver is aware of the length property of the Function prototype, but that is not the main point. Since there is a lot of nesting it is a good way to check how clearly the solver thinks in complicated scenarios.

Let me know in comments how you would solve it?

No I won't write it, currying is an inefficient antipattern in this example and then I'd walk out 😊

Thanks for a well written post though, the concept might sound confusing.

TusharShahi

God, you must be fun at interviews :P
Just kidding.
Honestly, I have also not used something like this in real world.

Under the right circumstances the strategy of calling out the drawbacks, running the interview (but doing the technical task well) can lead to a stronger position. And no, no I'm no fun 😊

TusharShahi

True. That makes sense.

TusharShahi

Follow up : How would you change your code if you have to handle this case too:

``````console.log(curriedJoin(1)(2)(3,4,5,6));
``````

Naveen Kumar Chintakindi

Hai I have reduced this custom curry function as below: