I am trying to re-implement redux compose function, instead of using reduce i use a for loop, here is my code:
function compose(...funcs) {
if (funcs.length === 0) {
return (arg) => arg;
}
if (funcs.length === 1) {
return funcs[0];
}
let result;
for (let i = funcs.length - 1; i > -1; i--) {
result = result
? (...args) => funcs[i](result(...args))
: (...args) => funcs[i](...args);
}
return result;
}
// test
function fn1(x) {
return x + 1;
}
function fn2(x) {
return x * 10;
}
function fn3(x) {
return x - 1;
}
console.log(compose(fn3, fn2, fn1)(10)); // 109
It is expected to log 109 since (10 + 1) * 10 - 1 is 109, however it gives me such error:
RangeError: Maximum call stack size
Looks like i am doing some recursion but all i did is just a for loop, no sure where is the problem of my code?
I think the issue is like the below example:
a = () => 2;
a = () => 3 * a();
console.log(a);
// this prints () => 3 * a() in console
// so when you call a(), it will call 3 * a(), which will again call 3 * a() and so on
// leading to infinite recursion
My solution is slightly different using bind function based on this reference link: https://stackoverflow.com/a/6772648/4688321.
I think bind creates a new copy of the function result and binds it to a new object. Not using bind leads to recursion because then the code becomes like the above example, result calls result.
function compose(...funcs) {
if (funcs.length === 0) {
return (arg) => arg;
}
if (funcs.length === 1) {
return funcs[0];
}
let result;
for (let i = funcs.length - 1; i > -1; i--) {
if (i == funcs.length - 1)
result = (...args) => funcs[i](...args);
else {
let temp = result.bind({});
result = (...args) => funcs[i](temp(...args));
}
}
return result;
}
// test
function fn1(x) {
console.log("fn1");
return x + 1;
}
function fn2(x) {
console.log("fn2");
return x * 10;
}
function fn3(x) {
console.log("fn3");
return x - 1;
}
//console.log(compose(fn3, fn2, fn1));
let ret = compose(fn3, fn2, fn1);
console.log(ret(10)); // 109
Rather than trying to combine functions at the time of compose, it seems much easier to combine them at the time the resulting function is called:
function compose(...funcs) {
if (funcs.length === 0) {
return (arg) => arg
}
return function (...args) {
let result = funcs .at (-1) (...args)
for (let i = funcs.length - 2; i > -1; i--) {
result = funcs [i] (result)
}
return result
}
}
// test
function fn1(x) {
return x + 1;
}
function fn2(x) {
return x * 10;
}
function fn3(x) {
return x - 1;
}
console.log(compose(fn3, fn2, fn1)(10)); // 109
However, again, reduce make for a much cleaner implementation:
const compose = (...fns) => (arg) =>
fns .reduceRight ((a, fn) => fn (a), arg)
or if you want to allow the rightmost function to receive multiple variables, then
const compose = (...fns) => (...args) =>
fns .reduceRight ((a, fn) => [fn (...a)], args) [0]
I am trying to build a spy function that will do this.
const func1 = function (x, y) {return x + y};
const func2 = spy(func1);
func2(2, 5) // => 7
func2(4, 5) // => 9
func2.calls() // => 2
func2.args() // => [[2, 5], [4, 5]]
I have created this function but I can seem to get the calls and args
function spy(func) {
let count = 0;
let allArgs = [];
function ispy() {
let args2 = Array.prototype.slice.call(arguments);
spy.calls = function() {
return count++;
}
spy.args = function() {
return allArgs.push(args2)
}
func.apply(this, args2);
}
return spy;
}
const func1 = function (x, y) {return x + y};
const func2 = spy(func1);
console.log(func2(2, 5))
console.log(func2.calls())
console.log(func2.args())
Please help me fix it and let me know what am I missing?
A few things,
You need to keep track of count and allArgs for every invocation of the spy call.
You need to return the result of the spied upon function from spy.
function spy(func) {
let count = 0;
let allArgs = [];
function spy() {
// increment count on every invocation
count++;
let args2 = Array.prototype.slice.call(arguments);
// shove arguments onto the allArgs array.
allArgs.push(args2);
spy.calls = function() {
return count;
}
spy.args = function() {
return allArgs;
}
//return the result;
return func.apply(this, args2);
}
return spy;
}
const func1 = function (x, y) {return x + y};
const func2 = spy(func1);
console.log(func2(2, 5))
console.log(func2.calls())
console.log(func2.args())
You add functions to spy in a call of ispy() and increment count in call of calls instead of call of ispy, you don't return result of func, you assign calls and args functions in every call to ispy and many other mistakes
function spy(func) {
let count = 0;
let allArgs = [];
function ispy(...args) {
count++;
allArgs.push(args);
return func.apply(this, args);
}
ispy.calls = function() {
return count;
}
ispy.args = function() {
return allArgs;
}
return ispy;
}
const func1 = function (x, y) {return x + y};
const func2 = spy(func1);
console.log(func2(2, 5));
console.log(func2(4, 5));
console.log(func2.calls())
console.log(func2.args())
You could take the arguments directly with rest parameters and return in the function only the value of the variables. The assignemnt should happen outside of the function, because if not it would require a call of func2 first.
Each call of ispy should be counted and the arguments should be added to.
function spy(func) {
function ispy(...args) {
count++;
allArgs.push(args);
return func.apply(this, args);
}
let count = 0;
let allArgs = [];
ispy.calls = () => count;
ispy.args = () => allArgs;
return ispy;
}
const func1 = function (x, y) {return x + y};
const func2 = spy(func1);
console.log(func2.calls())
console.log(func2(2, 5))
console.log(func2.calls())
console.log(func2.args())
I have tried writing the below code to find sum of 'n' numbers using sum function. I am getting the correct response in output. But i am unable to return that using sum function, as i always have to return a function, which is required for curried effect.
Please help. Thanks in advance.
var output = 0,
chain;
function sum() {
var args = Array.prototype.slice.call(arguments);
output += args.reduce(function(a, b) {
return a + b;
});
sumCurried = sum.bind(output);
sumCurried.val = function() {
return output;
}
return sumCurried;
}
debugger;
document.getElementById('demo').innerHTML = sum(1, 2)(3)(4);
// document.getElementById('demo').innerHTML = sum(1)(3)(4);
<p id='demo'></p>
enter code here
You can add a stop condition to the curried function, for example - if the function is called without an argument return the output:
var output = 0,
chain;
function sum() {
var args = Array.prototype.slice.call(arguments);
if(args.length === 0) {
return output;
}
output += args.reduce(function(a, b) {
return a + b;
});
sumCurried = sum.bind(output);
return sumCurried;
}
console.log(sum(1, 2)(3)(4)());
<p id='demo'></p>
The returned curry function has a val property, which is a function that returns the current value:
var output = 0,
chain;
function sum() {
var args = Array.prototype.slice.call(arguments);
output += args.reduce(function(a, b) {
return a + b;
});
sumCurried = sum.bind(output);
sumCurried.val = function() {
return output;
}
return sumCurried;
}
console.log(sum(1, 2)(3)(4).val());
<p id='demo'></p>
Why would you use currying at all? However, here is a shorter version:
const sum = (...args) => {
const func = (...s)=> sum(...args,...s);
func.value = args.reduce((a,b)=>a+b,0);
return func;
};
//usable as
sum(1,2).value,
sum(1,1)(1).value,
sum(1,1)(1,1)(1,1).value
And you always need to end the currying chain. However, it can be shortified:
func.valueOf = ()=> args.reduce((a,b)=>a+b,0);
//( instead of func.value = ... )
So when called you can do:
+sum(1,2,3)
+sum(1)(1)(1)
I need a js sum function to work like this:
sum(1)(2) = 3
sum(1)(2)(3) = 6
sum(1)(2)(3)(4) = 10
etc.
I heard it can't be done. But heard that if adding + in front of sum can be done.
Like +sum(1)(2)(3)(4). Any ideas of how to do this?
Not sure if I understood what you want, but
function sum(n) {
var v = function(x) {
return sum(n + x);
};
v.valueOf = v.toString = function() {
return n;
};
return v;
}
console.log(+sum(1)(2)(3)(4));
JsFiddle
This is an example of using empty brackets in the last call as a close key (from my last interview):
sum(1)(4)(66)(35)(0)()
function sum(firstNumber) {
let accumulator = firstNumber;
return function adder(nextNumber) {
if (nextNumber === undefined) {
return accumulator;
}
accumulator += nextNumber;
return adder;
}
}
console.log(sum(1)(4)(66)(35)(0)());
I'm posting this revision as its own post since I apparently don't have enough reputation yet to just leave it as a comment. This is a revision of #Rafael 's excellent solution.
function sum (n) {
var v = x => sum (n + x);
v.valueOf = () => n;
return v;
}
console.log( +sum(1)(2)(3)(4) ); //10
I didn't see a reason to keep the v.toString bit, as it didn't seem necessary. If I erred in doing so, please let me know in the comments why v.toString is required (it passed my tests fine without it). Converted the rest of the anonymous functions to arrow functions for ease of reading.
New ES6 way and is concise.
You have to pass empty () at the end when you want to terminate the call and get the final value.
const sum= x => y => (y !== undefined) ? sum(x + y) : x;
call it like this -
sum(10)(30)(45)();
Here is a solution that uses ES6 and toString, similar to #Vemba
function add(a) {
let curry = (b) => {
a += b
return curry
}
curry.toString = () => a
return curry
}
console.log(add(1))
console.log(add(1)(2))
console.log(add(1)(2)(3))
console.log(add(1)(2)(3)(4))
Another slightly shorter approach:
const sum = a => b => b? sum(a + b) : a;
console.log(
sum(1)(2)(),
sum(3)(4)(5)()
);
Here's a solution with a generic variadic curry function in ES6 Javascript, with the caveat that a final () is needed to invoke the arguments:
const curry = (f) =>
(...args) => args.length? curry(f.bind(0, ...args)): f();
const sum = (...values) => values.reduce((total, current) => total + current, 0)
curry(sum)(2)(2)(1)() == 5 // true
Here's another one that doesn't need (), using valueOf as in #rafael's answer. I feel like using valueOf in this way (or perhaps at all) is very confusing to people reading your code, but each to their own.
The toString in that answer is unnecessary. Internally, when javascript performs a type coersion it always calls valueOf() before calling toString().
// invokes a function if it is used as a value
const autoInvoke = (f) => Object.assign(f, { valueOf: f } );
const curry = autoInvoke((f) =>
(...args) => args.length? autoInvoke(curry(f.bind(0, ...args))): f());
const sum = (...values) => values.reduce((total, current) => total + current, 0)
curry(sum)(2)(2)(1) + 0 == 5 // true
Try this
function sum (...args) {
return Object.assign(
sum.bind(null, ...args),
{ valueOf: () => args.reduce((a, c) => a + c, 0) }
)
}
console.log(+sum(1)(2)(3,2,1)(16))
Here you can see a medium post about carried functions with unlimited arguments
https://medium.com/#seenarowhani95/infinite-currying-in-javascript-38400827e581
Try this, this is more flexible to handle any type of input. You can pass any number of params and any number of paranthesis.
function add(...args) {
function b(...arg) {
if (arg.length > 0) {
return add(...[...arg, ...args]);
}
return [...args, ...arg].reduce((prev,next)=>prev + next);
}
b.toString = function() {
return [...args].reduce((prev,next)=>prev + next);
}
return b;
}
// Examples
console.log(add(1)(2)(3, 3)());
console.log(+add(1)(2)(3)); // 6
console.log(+add(1)(2, 3)(4)(5, 6, 7)); // 28
console.log(+add(2, 3, 4, 5)(1)()); // 15
Here's a more generic solution that would work for non-unary params as well:
const sum = function (...args) {
let total = args.reduce((acc, arg) => acc+arg, 0)
function add (...args2) {
if (args2.length) {
total = args2.reduce((acc, arg) => acc+arg, total)
return add
}
return total
}
return add
}
document.write( sum(1)(2)() , '<br/>') // with unary params
document.write( sum(1,2)() , '<br/>') // with binary params
document.write( sum(1)(2)(3)() , '<br/>') // with unary params
document.write( sum(1)(2,3)() , '<br/>') // with binary params
document.write( sum(1)(2)(3)(4)() , '<br/>') // with unary params
document.write( sum(1)(2,3,4)() , '<br/>') // with ternary params
ES6 way to solve the infinite currying. Here the function sum will return the sum of all the numbers passed in the params:
const sum = a => b => b ? sum(a + b) : a
sum(1)(2)(3)(4)(5)() // 15
function add(a) {
let curry = (b) => {
a += b
return curry;
}
curry[Symbol.toPrimitive] = (hint) => {
return a;
}
return curry
}
console.log(+add(1)(2)(3)(4)(5)); // 15
console.log(+add(6)(6)(6)); // 18
console.log(+add(7)(0)); // 7
console.log(+add(0)); // 0
Here is another functional way using an iterative process
const sum = (num, acc = 0) => {
if !(typeof num === 'number') return acc;
return x => sum(x, acc + num)
}
sum(1)(2)(3)()
and one-line
const sum = (num, acc = 0) => !(typeof num === 'number') ? acc : x => sum(x, acc + num)
sum(1)(2)(3)()
You can make use of the below function
function add(num){
add.sum || (add.sum = 0) // make sure add.sum exists if not assign it to 0
add.sum += num; // increment it
return add.toString = add.valueOf = function(){
var rtn = add.sum; // we save the value
return add.sum = 0, rtn // return it before we reset add.sum to 0
}, add; // return the function
}
Since functions are objects, we can add properties to it, which we are resetting when it's been accessed.
we can also use this easy way.
function sum(a) {
return function(b){
if(b) return sum(a+b);
return a;
}
}
console.log(sum(1)(2)(3)(4)(5)());
To make sum(1) callable as sum(1)(2), it must return a function.
The function can be either called or converted to a number with valueOf.
function sum(a) {
var sum = a;
function f(b) {
sum += b;
return f;
}
f.toString = function() { return sum }
return f
}
function sum(a){
let res = 0;
function getarrSum(arr){
return arr.reduce( (e, sum=0) => { sum += e ; return sum ;} )
}
function calculateSumPerArgument(arguments){
let res = 0;
if(arguments.length >0){
for ( let i = 0 ; i < arguments.length ; i++){
if(Array.isArray(arguments[i])){
res += getarrSum( arguments[i]);
}
else{
res += arguments[i];
}
}
}
return res;
}
res += calculateSumPerArgument(arguments);
return function f(b){
if(b == undefined){
return res;
}
else{
res += calculateSumPerArgument(arguments);
return f;
}
}
}
let add = (a) => {
let sum = a;
funct = function(b) {
sum += b;
return funct;
};
Object.defineProperty(funct, 'valueOf', {
value: function() {
return sum;
}
});
return funct;
};
console.log(+add(1)(2)(3))
After looking over some of the other solutions on here, I would like to provide my two solutions to this problem.
Currying two items using ES6:
const sum = x => y => (y !== undefined ) ? +x + +y : +x
sum(2)(2) // 4
Here we are specifying two parameters, if the second one doesnt exist we just return the first parameter.
For three or more items, it gets a bit trickier; here is my solution. For any additional parameters you can add them in as a third
const sum = x => (y=0) => (...z) => +x + +y + +z.reduce((prev,curr)=>prev+curr,0)
sum(2)()()//2
sum(2)(2)()//4
sum(2)(2)(2)//6
sum(2)(2)(2,2)//8
I hope this helped someone
When using bind in JS, one can create functions with predefined arguments, e. g.:
var add = function (a, b) {
return a + b;
};
var addToThree = add.bind(null, 3);
But how to I do this if I want to predefine the second, third etc. argument, but not the first?
In ES2015 you can do something like this:
const partial = fn => (...pargs) => (...args) => fn.apply(null, [...pargs, ...args]);
const partialRight = fn => (...pargs) => (...args) => fn.apply(null, [...args, ...pargs.reverse()]);
const myFunc = (one, two, three, four) => {
console.log(one);
console.log(two);
console.log(three);
console.log(four);
};
const myFuncPartial = partial(myFunc)('1');
const myFuncPartialRight = partialRight(myFuncPartial)('4', '3');
myFuncPartialRight('2');
You can do
var add = function (a, b) {
b = b || 5;
return a + b;
};
In ES6 Default Parameters can be used in a very easy way
var add = function (a, b=5) {
return a + b;
};
and call it like add(3);