Currying in javascript for function with n parameters - javascript

If f :: (a, b) -> c, we can define curry(f) as below:
curry(f) :: ((a, b) -> c) -> a -> b -> c
const curry = f => a => b => f(a, b);
const sum = curry((num1, num2) => num1 + num2);
console.log(sum(2)(3)); //5
How do we implement generic curry function that takes a function with n parameters?

If I understand correctly, I think this is the way to go using ES6:
const curry = f => {
const nargs = f.length;
const vargs = [];
const curried = (...args) => vargs.push(...args) >= nargs
? f(...vargs.slice(0, nargs))
: curried;
return curried;
};
const fn2 = curry((a, b) => a + b);
const fn3 = curry((a, b, c) => a * (b + c));
const fn4 = curry((a, b, c, d) => Math.pow(a, b * (c + d)));
console.log(fn2(1)(2)); // 1 + 2
console.log(fn3(2)(3)(4)); // 2 * (3 + 4)
console.log(fn4(2)(1, 3)(4)); // 2 ^ (1 * (3 + 4))
If you want to do this in ES5, here's a slightly more verbose method:
function curry (f) {
var nargs = f.length;
var vargs = [];
return function curried () {
return vargs.push.apply(vargs, arguments) >= nargs
? f.apply(undefined, vargs.slice(0, nargs))
: curried;
};
}
var fn2 = curry(function (a, b) {
return a + b;
});
var fn3 = curry(function (a, b, c) {
return a * (b + c);
});
var fn4 = curry(function (a, b, c, d) {
return Math.pow(a, b * (c + d));
});
console.log(fn2(1)(2)); // 1 + 2
console.log(fn3(2)(3)(4)); // 2 * (3 + 4)
console.log(fn4(2)(1, 3)(4)); // 2 ^ (1 * (3 + 4))

Caveat: I don't have a functional background, so my terminology may be a bit off.
If by "curry" you mean "create a new function that will call the original with some arguments pre-filled," the general solution in ES5 and earlier is as follows (see comments):
// Add a function to the function prototype
Object.defineProperty(Function.prototype, "curry", {
value: function() {
// Remember the original function
var f = this;
// Remember the curried arguments
var args = Array.prototype.slice.call(arguments);
// Return a new function that will do the work
return function() {
// The new function has been called: Call the original with
// the curried arguments followed by any arguments received in
// this call, passing along the current value of `this`
return f.apply(this, args.concat(Array.prototype.slice.call(arguments)));
};
}
});
// Usage:
function foo(a, b, c) {
console.log(a, b, c);
}
var f = foo.curry(1, 2);
f(3);
In ES2015+, we can use rest args instead of arguments:
// REQUIRES ES2015+ support in your browser!
// Add a function to the function prototype
Object.defineProperty(Function.prototype, "curry", {
value: function(...curriedArgs) {
// Remember the original function
let f = this;
// Return a new function that will do the work
return function(...args) {
// The new function has been called: Call the original with
// the curried arguments followed by any arguments received in
// this call, passing along the current value of `this`
return f.apply(this, curriedArgs.concat(args));
};
}
});
// Usage:
function foo(a, b, c) {
console.log(a, b, c);
}
let f = foo.curry(1, 2);
f(3);

ES6/2015
const curry = fn => function curried(cargs) {
return cargs.length >= fn.length ? fn.apply(this, cargs) : (...args) => curried([...cargs, ...args])
}([]);
const arg2 = curry((a, b) => a + b);
const arg3 = curry((a, b, c) => a * (b + c));
const arg4 = curry((a, b, c, d) => Math.pow(a, b * (c + d)));
console.log(arg2(1)(2)); // 1 + 2
console.log(arg3(2)(3)(4)); // 2 * (3 + 4)
console.log(arg4(2)(1, 3)(4)); // 2 ^ (1 * (3 + 4))
ES5
var curry = function(fn) {
var args = Array.prototype.slice.call(arguments);
if (args.length - 1 >= fn.length) return fn.apply(this, args.slice(1));
return function() {
return curry.apply(this, args.concat.apply(args, arguments));
};
};
var arg2 = curry(function(a, b) {
return a + b;
});
var arg3 = curry(function(a, b, c) {
return a * (b + c);
});
var arg4 = curry(function(a, b, c, d) {
return Math.pow(a, b * (c + d));
});
console.log(arg2(1)(2)); // 1 + 2
console.log(arg3(2)(3)(4)); // 2 * (3 + 4)
console.log(arg4(2)(1, 3)(4)); // 2 ^ (1 * (3 + 4))

There's a simple way to curry your sum function with unlimited parameters.
const add = (a) => {
const next = b => add(a + b);
next.valueOf = () => a
return next;
};
const one = add(1);
console.log(one.valueOf());
const two = one + 1;
console.log(two);
const four = two + two;
console.log(four)
const six = add(four)(two);
console.log(six.valueOf());
const eleven = six(4)(1);
console.log(eleven.valueOf());
This add function would run every time you call the curried function with another parameter. Like in the case for const six = four + two;It returns the value from two previous calls and the chain goes on and on.
Keep in mind that in order to get the primitive value we need to call .valueOf().

Below is a solution inspired by Juan Sebastián Gaitán's solution I have just extended it for below cases:
add(1, 2)(2, 3)(1, 2, 3, 4).valueOf();
add(1,2,3,4).valueOf();
add(1)(2)(3)(4)(5).valueOf();
const add = (a, ...rest) => {
a += rest.reduce((total, val) => {
return total + val;
}, 0);
const next = (...b) => add(a + b.reduce((total, val) => {
return total + val;
}, 0));
next.valueOf = () => a;
//console.log('a', a, '; next: ', next, '; rest: ', ...rest);
return next;
};
console.log(add(1, 2)(2, 3)(1, 2, 3, 4).valueOf()); //18
console.log(add(1,2,3,4).valueOf()); //10
console.log(add(1)(2)(3)(4)(5).valueOf()); //15
As the output is a function, you need valueOf(). to get the value.
the function looks little cumbersome because of .reduce() but its very simple to read.
This is a good example of recursive function and a currying function.

Related

How would i make a function for it as well which will keep track of the empty values of second argument

multiply(10)()()()(12)
This a function call and we have to make a function to multiply 2 numbers
You can curry the function and leverage rest parameters and spreading. If there are no arguments supplied then (...args) will be an empty array and .bind(this, ...args) will create a function without partially applying any values to it.
Once all arguments are satisfied, the function is immediately called.
const curry = f => function(...args) {
if (f.length - args.length <= 0)
return f.apply(this, args);
return curry(f.bind(this, ...args));
}
const mul = (a, b) => a * b;
const multiply = curry(mul);
console.log(multiply(10, 12)); // = 120
console.log(multiply(10)(12)); // = 120
console.log(multiply(10)()(12)); // = 120
console.log(multiply(10)()()()(12)); // = 120
const obj = {
x: 2,
multiply: curry(function(a, b) {
return a * b * this.x;
})
}
console.log(obj.multiply(10)()()()(12)); // = 240

Finding the sum of a curry function?

var curry = function (func) {
return function (a) {
return function (b) {
return function (c) {
return function (d) {
return function (e) {
return func (a, b, c, d, e);
}
}
}
}
}
}
var getSum=curry(a+b+c+d+e);
console.log(getSum(15)(20)(25)(30)(35));
This is my code so far, but it's saying a is not defined and I'm not sure how to fix it. If I do this with Math.max it works, how can I achieve the same thing but with a sum instead of max?
By defining a function that sums its arguments, just like Math.max finds the max of its arguments:
const curry = function (func) {
return function (a) {
return function (b) {
return function (c) {
return function (d) {
return function (e) {
return func (a, b, c, d, e);
};
};
};
};
};
};
const getSum = (...args) => {
return args.reduce((sum, value) => sum + value, 0);
};
console.log(curry(getSum)(15)(20)(25)(30)(35));
Curry is expecting a function with your decleration
var curry = function (func) {...}
You should be calling it with a function. However you're attempting to resolving some variables and add them then just pass the number. What you have here is a Higher Order Function, or a Function which takes a Function and returns a Function.
var getSum=curry(a+b+c+d+e); // not passing a function
Your code however is attempting to do the following:
var temp = a+b+c+d+e;
var getSum=curry(temp);
The problem is that now it's attempting to find a global a, b, c, d, and e variable, to sum them, and then pass that to curry... which fails as soon as it tries to find a global a. What you want to pass is a function.
var getSum = curry((...arg) => args.reduce((acc, value) => acc + value));
This is a function that takes a variable amount of arguments, so when you pass it to curry it will return a function(a internal to curry scope), which when called will return a function(b to a scope) which will return a fun.... so on and so forth until it finally calls the last time and sums them all after the last call.
Another more advanced version of an automatic curry function with examples from 30 Seconds of Code
const curry = (fn, arity = fn.length, ...args) =>
arity <= args.length ? fn(...args) : curry.bind(null, fn, arity, ...args);
curry(Math.pow)(2)(10); // 1024
curry(Math.min, 3)(10)(50)(2); // 2
Other versions of Curry exist in other places like RamdaJS, but you get the idea. It's a higher order function that continuously returns functions until you've supplied enough arguments to satisfy it's arity(how many arguments it wants).
You need to supply a function for the five parameters and take the function for the first call of curry.
var curry = function(func) {
return function(a) {
return function(b) {
return function(c) {
return function(d) {
return function(e) {
return func(a, b, c, d, e);
}
}
}
}
}
}
var getSum = function (a, b, c, d, e) { return a + b + c + d + e; };
console.log(curry(getSum)(15)(20)(25)(30)(35));
A dynamic approach without binding.
var curry = fn => {
const
curried = p => (...args) => {
p = [...p, ...args];
return p.length < fn.length
? curried(p)
: fn(...p);
};
return curried([]);
},
getSum = (a, b, c, d, e) => a + b + c + d + e;
console.log(curry(getSum)(15)(20)(25)(30)(35));
var add = curry((a, b, c, d) => a + b + c + d),
add1 = add(1),
add2 = add(2)(3)(4);
console.log(add1() === 10); // false
A dynamic approach for curry function. Here What I have done is curry function takes the function to be curried func returns a new function temp.
Inside temp we check if length of arguments of temp is less than the number of arguments required for the original function func.
If it is less we return temp again with the arguments received, else call the original function func with all the arguments
var getSum = function (a, b, c, d, e) { return a + b + c + d + e; };
function curry(func){
return function temp(...args) {
if (args.length < func.length) {
return temp.bind(null, ...args)
}
return func(...args)
}
}
console.log(curry(getSum)(15)(20)(25)(30)(35));

Convert functional js function to general case

I wonder how i can convert this curry function to work with n number of variables instead of 2.
so for example i want to invoke:
curry(mul)(3)(3)(3) -> and get 27
(with a fixed version of curry)
function curry(fn) {
return function() {
if (fn.length > arguments.length) {
var slice = Array.prototype.slice;
var args = slice.apply(arguments); // get arguments as args array
return function() {
return fn.apply(null, args.concat(slice.apply(arguments)));
};
}
return fn.apply(null, arguments);
};
}
// mul is just an example it can be any function....
function mul(x, y) {
console.log(x * y)
}
curry(mul)(11)(5)
This question makes me think of food .. but you can try this version:
const curry = (fn, ...args) =>
args.length < fn.length ? (...args2) => curry(fn, ...args, ...args2) : fn(...args);
const mul = (a, b, c) => console.log(a * b * c);
curry(mul)(3)(3)(3)
curry(mul)(3, 3)(3)
curry(mul, 3, 3, 3, 3) // extra parameters are ignored by mul
IE version here https://www.typescriptlang.org/play/index.html#src=const%20curry%20%3D%20(fn...

How to create a variadic high-order function reusing the returned result in JS

Consider I have an undetermined number of functions f, each one needing one argument and returning one result. How should I write a function "execute" taking the first argument as the number, and all the other arguments as functions to be applied to the result of each preceding function?
Here's my guess:
let plus1 = d => d += 1;
let plus2 = d => d += 2;
let write = d => document.write(d);
let execute = function(n,...functions){
functions.forEach((d)=>d(n));
}
execute(4,plus1,plus2,write);
I'm expecting 7 ((4+1)+2).
Thanks for your help!
You could use Array#reduce, which returns a result, while using a function with a given value.
let plus1 = d => d + 1,
plus2 = d => d + 2,
write = d => console.log(d),
execute = (n, ...fn) => fn.reduce((n, f) => f(n), n);
execute(4, plus1, plus2, write);
Shorter version as Yury Tarabanko suggested
let plus1 = d => d + 1,
plus2 = d => d + 2,
write = d => console.log(d),
execute = (...args) => args.reduce((v, f) => f(v));
execute(4, plus1, plus2, write);
The monoidal combination of two functions does exactly what you want: it propagates an argument through all the combined functions, the difference with your example is that all the results are later combined by another monoidal combination:
function monoidCombine(f, g) {
let ftype = typeof f;
let gtype = typeof g;
if (ftype === "function" && gtype === "function") {
return function(input) {
return monoidCombine(f(input), g(input));
};
}
if (ftype === "number" && gtype === "number") {
return f + g;
}
throw new Error(`No case for monoidCombine(${ftype}, ${gtype})`);
}
function execute(n, ...functions) {
return functions.reduce((f, g) => monoidCombine(f, g))(n);
}
execute(1, (x) => x + 3, (x) => x + 1);
// ^-- is equivalent to ((x) => x + 3)(1) + ((x) => x + 1)(1)
// so the result is 6

Javascript: How to store a declared function in a variable?

I'm learning Javascript and wondering if it's possible to store a declared function in a variable to be used later?
For context,
function add(a, b) {
return a + b;
}
var addTogether = _.partial(add, 1);
doSomething() // returns a promise that resolves to a 2
.then(addTogether); // expect to return 3
Is there a way to achieve this?
var Add = function (a, b)
{
return a + b;
}
var result = Add (2, 3);
Absolutely. Functions ARE data in JavaScript.
var foo = function(a, b) {
return a + b;
}
Is perfectly legitimate.
function add(a, b) {
return a + b;
}
var foo = add;
console.log(foo(5,10));
console.log(add(10, 20));
You can also use ES6 syntax to store anonymous functions in constants, like so:
const add = (a, b) => a + b;
const addOne = a => add(a, 1);
console.log(add(5, 10)); // 15
console.log(addOne(5)); // 6

Categories

Resources