I wanted to create a curried add
function that allows for unlimited chaining, like add(1)(2)...(n)
. I started with a curry
function that returns a curried version of the input function:
const curry = (fn) => {
const curried = (...args) => {
if (args.length >= fn.length) {
return fn(...args);
}
return (...moreArgs) => curried(...args, ...moreArgs);
};
return curried;
}
Next, I tried to use curry
to create a curriedAdd function with fixed parameters:
const add = (a , b) => a + b
const curriedAdd = curry(add)
console.log(curriedAdd(2, 3))
// 5
console.log(curriedAdd(2)(3))
// 5
console.log(curriedAdd(2)(3)(4))
// Oops an error!
// Uncaught TypeError: curriedAdd(...)(...) is not a function at <anonymous>:5:29
However, I encountered a problem while trying to achieve unlimited chaining using the currying technique. JavaScript functions have a fixed number of parameters, which makes it impossible to create a function that can accept an unlimited number of arguments without using some sort of workaround.
When we call curriedAdd(2)
, it returns a function that takes another parameter and adds it to 2. Therefore, curriedAdd(2)(3)
results in a number 5.
But attempting to call 5(4)
leads to a runtime error since 5 is a number and not a function that can accept another argument.
Instead, I came up with a solution that involves returning a function that can be called with an empty argument to indicate the end of the chain. With this approach, the user needs to manually call the function with an empty argument ()
to signal the end of the chain.
Although this requires a bit more effort from the user to call the execution, it allows for an unlimited number of arguments to be passed in a curried manner, as demonstrated by add(1)(2)...(n)()
.
const add = (x) => {
let sum = x;
const innerAdd = (y) => {
if (y !== undefined) {
sum += y;
return innerAdd;
} else {
return sum;
}
};
return innerAdd;
};
add(1)(2)(3)(); // returns 6
add(1)(2)(3)(4)(5)(); // returns 15
Alternatively, if we know the expected number of parameters ahead of time, we can use curry with a fixed number of arguments:
const curryN = (fn, fnArgsLen = fn.length) =>
(...args) =>
args.length >= fnArgsLen
? fn(...args)
: (...moreArgs) => curryN(fn, fnArgsLen)(...args, ...moreArgs);
const add = (x, y, z) => x + y + z
const curriedAdd = curryN(add, 3);
console.log(curriedAdd(1)(2)(3)); // prints 6
console.log(curriedAdd(1, 2)(3)); // prints 6
console.log(curriedAdd(1, 2, 3)); // prints 6
While this approach isn't truly unlimited chaining, it can handle a large number of arguments and provides a flexible way to compose functions.
Top comments (0)