Convert functional js function to general case - javascript

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...

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));

Evaluating Nested function call represented as string

how to solve nested function call represented as string in javascript
as "PRODUCT(SUM(PRODUCT(2,2),2),3)" => 18
as "SUM(12,PRODUCT(1,2))" => 14
This would be easy using eval().But need to do without using eval().
const SUM = (...args) => args.reduce((a, b) => a + b);
const PRODUCT = (...args) => args.reduce((a, b) => a * b);
const evaluateString = str => {
//code to evaluate "PRODUCT(SUM(PRODUCT(2,2),2),3)"
}
As Yeldar said the cleanest way to do it would be to create syntax tree and to evaluate it but with your given example it looks like you will always get only 2 args since your functions just implement trivials operators. Given those informations it would be a pain to code for such a basic use so i recommand to create your own evaluator in this case.
Ok this is clearly not a very clean way to do and their is probably a lot of possible upgrades but here is a piece of code doing the job :
const SUM = (...args) => args.reduce((a, b) => a + b);
const PRODUCT = (...args) => args.reduce((a, b) => a * b);
const strToEvaluate = "PRODUCT(SUM(PRODUCT(2,2),PRODUCT(SUM(1,1),2)),3);";
function myEval(str) {
if(!isNaN(str)) {
return Number(str);
}
if(str.includes('(')) {
let fn = str.split('(')[0];
let pos = getParenthesisAndComaPos(str.substring(str.indexOf('(')+1));
let arg1 = myEval(str.substring(str.indexOf('(')+1).substring(0, pos[0]));
let arg2 = myEval(str.substring(str.indexOf('(')+1).substring(pos[0]+1, pos[1]));
switch(fn) {
case 'PRODUCT':
return PRODUCT(arg1, arg2);
case 'SUM':
return SUM(arg1, arg2);
}
}
}
//Will return a tab with position of the coma between arg0 and arg1 and position of the end parenthesis
function getParenthesisAndComaPos(str) {
let counter = 1;
let i=0;
let c=0;
while (counter>0 && i<=str.length) {
if(counter==1 && str.charAt(i)==',') {
c = i;
}
if(str.charAt(i)==')') {
counter--;
} else if(str.charAt(i)=='(') {
counter++;
}
i++;
}
return [c, i-1];
}
console.log(myEval(strToEvaluate));

Is it possible to create sum function from reduce and curry without inline functions?

I want to create function sum out of curry and reduce if I have standard functions apply and call:
My try:
// those are init functions:
function type(label, arg, type) {
// some type checking so you know which function
// throw exception and why
var arg_type;
if (arg instanceof Array) {
arg_type = 'array';
} else if (arg === null) {
arg_type = 'null';
} else {
arg_type = typeof arg;
}
if (arg_type !== type) {
throw new Error(`${label}: Expecting ${type} got ${arg_type}`);
}
}
function curry(fn, ...init_args) {
type('curry', fn, 'function');
var len = fn.length;
return function() {
var args = init_args.slice();
function call(...more_args) {
args = args.concat(more_args);
//console.log({fn, len, args});
if (args.length >= len) {
return fn.apply(this, args);
} else {
return call;
}
}
return call.apply(this, arguments);
};
}
function reduce(fn, init, ...lists) {
if (lists.some(l => !l.length)) {
return init;
}
type('reduce', fn, 'function');
lists.forEach(a => type('reduce', a, 'array'));
const head = lists.map(l => l[0]);
const rest = lists.map(l => l.slice(1));
return reduce(fn, fn(...head, init), ...rest);
}
function apply(fn, args) {
type('apply', fn, 'function');
type('apply', args, 'array');
return fn.apply(null, args);
}
function call(fn, ...args) {
type('call', fn, 'function');
return fn.call(null, ...args);
}
var add = (a, b) => a + b;
// and this only using those without new inline function
var sum = curry(call, curry(reduce, add));
console.log(sum(1, 2, 3, 4));
var sum = curry(apply, curry(reduce, add));
console.log(sum(1, 2, 3, 4));
Is it possible to create sum function with: curry, apply, reduce and/or call? If not is it possible to add some generic known function that will allow to create sum without inline functions (this include arrow functions)?
I can create sum functions like this:
var sum = (...args) => reduce(add, 0, args);
so it seems what I need is function that get list of arguments and call function as array.
function caller(fn, ...args) {
return fn.call(null, args);
}
var sum = curry(caller, curry(reduce, add, 0));
console.log(curry(reduce, add, 0)([1,2,3,4]));
console.log(sum(1, 2, 3, 4));
function spread(fn) {
return function(...args) {
return call(fn, args);
};
}
var sum = spread(curry(reduce, add, 0));
console.log(sum(1, 2, 3, 4));
Does functions like caller and spread have some common name? Or is there a better way to create sum function, with those requirement? I can also use pipe or compose functions because they are also common, not sure if you can use them to create sum.
So basically my question is this, is possible to create sum function using any known function in functional libraries without any inline functions? Builtin functions like bind are also allowed.
This can be generalized to create a function from function two arguments that can be called with any arguments and it reduce on each argument without using inline function.
I want to know this because I want to know more about function programming.
I have no idea what you mean by inline functions.
But:
function ad = (a, b) => a + b;
function sum (...args) {
return args.reduce(add, 0);
}
console.log(sum(1, 2, 3, 4));
EDIT: Didn't understand the original question, here is the answer
// From lodash, is named differently in other FP libraries
const partialRight = (func, ...boundArgs) => (...remainingArgs) =>
func(...remainingArgs, ...boundArgs);
// From Lodash
const rest = (fn) => (...args) => fn(args);
// From any FP library
const reduce = function(iterable, reduceFn, accumulator){
for(let i of iterable){
accumulator = reduceFn(accumulator, i)
}
return accumulator
}
const add = (a, b) => a + b;
const sum = rest(partialRight(reduce, add, 0));
console.log(sum(1, 2, 3, 4));

Currying in javascript for function with n parameters

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.

Categories

Resources