Say I have a function called multiplyDivide
If I were to call multiplyDivide(2)(3)(4)(6)
it would be equivalent to 2 * 3 / 4 * 6
.
Update:
Is it possible to write a function like this if I don't know in advance how many parameters I will be taking? For example, I could have multiplyDivide(1)(2)
or multiplyDivide(1)(2)(3)(4)...(n-1)(n)
So if you'd like to make a function that accepts any number of positional arguments, use the * operator.
As my bonus tip, here is a modern way of implementing currying using the ES6 arrow function. It helps you write less code: const sendRequest = greet => name => message => `${greet} ${name}, ${message}` sendRequest('Hello')('John')('Please can you add me to your Linkedin network? ')
The following basic example uses currying. function multiply(a, b, c) { return a * b * c; } function multiply_curried(a) { return function (b) { return function (c) { return a * b * c } } } let res = multiply(1, 2, 3); console. log(res); let mc1 = multiply_curried(1); let mc2 = mc1(2); let res2 = mc2(3); console.
Curry functions are neat when used to carry containers of reusable code. Basically you take a function with multiple arguments and you know that one of those arguments will have specific value but the other is undecided.
It's sort of possible but you need to define the terminating condition because the problem is essentially the same problem as writing a recursive function. The function needs a way to tell whether it should return a function or a value.
How you signal the need for values is up to you. One way of doing it is to check if an argument is passed:
// Using add instead of multiplyDivide to simplify example:
function add (num) {
function adder (n) {
if (n !== undefined) {
num += n;
return adder;
}
else { // terminate
return num;
}
}
return adder;
}
Now you can do:
var sum = add(1)(2)(3)(4)();
Otherwise it would return a function which you can keep calling:
var x = add(1)(2)(3)(4);
x = x(5)(6)(7);
x = x(8)(9)(10);
var sum = x();
Since in js functions are objects, you can also implement the value getter as a static method. It won't be purely functional but makes the "API" a bit more explicit and easier to read:
function add (num) {
function adder (n) {
num += n;
return adder;
}
adder.value = function(){
return num
};
return adder;
}
Which would allow you to do:
var sum = add(1)(2)(3)(4).value();
You can even get fancy by overriding the built-in .valueOf()
and .toString()
methods:
function add (num) {
function adder (n) {
num += n;
return adder;
}
adder.valueOf = function(){
return num
};
adder.toString = function(){
return '' + num
};
return adder;
}
Which would allow you to do:
var sum = add(1)(2)(3)(4) + 5; // results in 15
var txt = add(1)(2)(3)(4) + "hello"; // results in "10hello"
The key here is that you need a way to tell the function to stop returning functions.
Using a functional approach, you can create a function that "curries" arguments for another function. You will need a way to tell the function to return the value, so in this case, calling the function without passing any arguments will return the result:
function curry(fn, ...values) {
return (...next) => (next.length) ? curry(fn, ...values, ...next) : fn(...values);
}
The cool thing about this function is that you can pass multiple arguments and/or keep invoking the function (1)(2, 3, 4)(5)
.
Here's a couple of examples:
function curry(fn, ...values) {
return (...next) => (next.length) ? curry(fn, ...values, ...next) : fn(...values);
}
function multiplyDivide(...args) {
return args.reduce((total, next, i) => (i % 2) ? (total / next) : (total * next), args.shift());
}
let x = curry(multiplyDivide)(2)(3, 4)(6)();
console.log(x);
let y = curry(multiplyDivide)(5, 4, 2)(3);
y = y(3, 5)(1)();
console.log(y);
Of course, this example does hint at just simply overloading the multiplyDivide
function and passing your values to that when you're ready:
function multiplyDivide(...args) {
return args.reduce((total, next, i) => (i % 2) ? (total / next) : (total * next), args.shift());
}
const values = [5, 4, 2, 3, 3];
values.push(5, 1);
console.log(multiplyDivide(...values));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With