As part of a programming challenge, we are tasked with creating a function with an undetermined number of successive calls. As an example, let's say the function returns simply the sum of the provided arguments, it should work as follows :
sum(4)() // 4
sum(4)(5)() // 9
sum(4)(5)(9)() // 18
sum(4)(5)(9)(1)() // 19
// etc...
The problem is simplified by the allowed empty function call at the end as an indication of end of calls.
I have worked on a solution that does the job but using global variables inside the function itself :
var sum = function (a) {
if (!sum.init) {
sum.total = 0;
sum.init = true;
}
if (!arguments.length) {
sum.init = false;
return sum.total;
}
sum.total += a;
return sum;
};
This solution works but uses state, global variables and function object trickery which is not ideal. My question here is whether there is a way to solve the problem in a purely recursive way.
As a side note, I do not believe the problem can be solved if that last empty call () is not provided, but if I'm wrong please let me know.
Update
This issue has been answered in CodeReview : https://codereview.stackexchange.com/a/153999/129579
A neet solution that does not rely on global scope and is purely functional.
You can make use of closures to acheive what you want like this:
function sum(value){
// the closure variable that will be accessible for all the _sum calls (initialised to 0 for every sum call).
var result = 0;
// the function that will be returned (sum will only get called once to initialize the result to 0. It's _sum which will be returned as much as possible)
function _sum(a){
// if we passed a parameter, then add it to result and return a new _sum
if(typeof a != "undefined"){
result += a;
return _sum;
}
// if we didn't return the result
else
return result;
}
// of course after initializing result we need to call _sum that handle the actual summing and return whatever it returns (if value is defined, it will return another `_sum` if not it will return the value of result which will be 0 at first) from now on sum will have nothing to do with the rest of the calls (()()()... )
return _sum(value);
}
console.log("sum() = " + sum());
console.log("sum(7)() = " + sum(7)());
console.log("sum(5)(6)(7)() = " + sum(5)(6)(7)());
// will return 0 because we call sum again
console.log("sum() = " + sum());
NOTE: That sum(1)(7)(3)()); will call, in this order:
sum with the parameter 1 which will initialize result to 0 and call
_sum with the same parameter 1 which will add it to result and return a new inctance of _sum which will be called so the following
_sum get called with the parameter 7, add it and return a new _sum so the new
_sum get called with the parameter 3, ... spawn another
_sum that will have no parameter, therefore if(typeof a != "undefined") will fail and this _sum will return result instead.
The actual sum is only called once at the begining to do the initialization. It's, as I said, _sum that get chained after that all the way to the end.
Basically you could use an outer function sum for the initial call and a closure over the starting value a and an inner function fn, which is repeatingly returned and only exited if arguments.length is equal to zero.
If a value b is supplied, the variable a gets updated and the inner function fn gets returned.
function sum(a) {
return function fn(b) {
if (!arguments.length) {
return a;
}
a += b;
return fn;
};
}
console.log(sum(1)());
console.log(sum(1)(2)());
console.log(sum(1)(2)(3)());
Edit for calling sum with no argument
function sum(a) {
return arguments.length ?
function fn(b) {
if (!arguments.length) {
return a;
}
a += b;
return fn;
} :
0;
}
console.log(sum());
console.log(sum(1)());
console.log(sum(1)(2)());
console.log(sum(1)(2)(3)());
Related
in need of help with a codecamp challenge:
Arguments Optional - The challenge
https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/arguments-optional
My Question
I know this can be done with the arguments object (see figure 1), where I can call the function again when the second value is undefined so I've gone for a different approach; However, my code of using currying works but becomes an issue with 'addTogether(5)(7);'
Issue ->
I get the returned value of 12 but doesn't get approved in the code challenge.
I did originally return the value inside the sum function but the challenge required the sum value to be returned in addTogether function, which I did so now it resulting in the following
addTogether(2,3); // now working
addTogether(5)(7); // NOT working
addTogether(23, 30); // now working
Is there something I'm doing wrong that's resulting in the test case failing even though the correct value is returned?
let val = 0;
function sum(a, b) {
val = a + b;
}
function sumTwoAnd(sumFunc) {
return function addTogether(...params) {
let numsArr = [...params];
const res = numsArr.every(el => typeof el === 'number');
if (res === false) return;
if (numsArr.length >= sumFunc.length) {
sumFunc(...numsArr);
} else {
return function(...args2) {
let newArr = numsArr.concat(args2);
addTogether(...newArr);
}
}
console.log(val);
return val;
}
}
let addTogether = sumTwoAnd(sum);
addTogether(2,3);
addTogether(5)(7);
addTogether(23, 30);
Figure 1
Shows how I can get 'test(5)(7)' the second parameter from the function
function test() {
const [f, s] = arguments;
console.log(f, s)
if (s === undefined) {
return s => test(f, s)
}
}
test(23, 30);
test(5)(7);
You declared addTogether using let, so the declaration won't be hoisted above the point where it was defined. This is making your recursive call in the else statement fail, since addTogether() doesn't exist that far up.
You might want to extract the function you're returning in sumTwoAnd() as a separate function definition, so it can freely call itself, similar to your Figure 1 example.
Or you can call sumTwoAnd() instead to regain the function, then pass newArr to said function.
Instead of calling the function I have now returned it...
return addTogether(...newArr);
This now works :)
I have been looking at this code for sometime now, trying to understand what it does but I can't really get my head around it. I need help with understanding what this function actually does
function element(array, gen) {
if(gen === undefined) {
gen = fromTo(
0,
array.length
);
}
return function() {
var index = gen();
if(index !== undefined) {
return array[index];
}
};
}
function concat(...gens) {
var next = element(gens),
gen = next();
return function recur() {
var value = gen();
if(value === undefined) {
gen = next();
if(gen !== undefined) {
return recur();
}
}
return value;
};
}
element is not a javascript built-in which means it must be defined elsewhere. Without knowing its function, it is impossible to say exactly what is happening, but here is what I can tell you.
concat takes n arguments of the same type. Without knowing what element does I can't tell you what type that is, but it can take as many as you need to give it. That is what the spread operator ... is telling you.
It returns a function that takes 0 arguments. When called, it continues to call itself checking if the return value of gen() is defined, if it is not, it changes gen to be the return value of next() and calls gen() again. It repeats this process until the return value of gen() is defined, and then returns that value.
Using it would look something like this.
var recur = concat(a,b,c,d,e); // can take any number of arguments of the same type
var someValue = recur(); // calls itself until it has a value to return
console.log(someValue); // use the value
I came across this pattern in redux compose function. I still don't understand how in the example below the functions are evaluated starting from the last and not from the first:
function f2(a) {
return a + a;
}
function f3(a) {
return a + a + a;
}
function f4(a) {
return a + a + a + a;
}
function f5(a) {
return a + a + a + a + a;
}
function compose(...funcs) {
return funcs.reduce(function x(a, b) {
return function y(...args) {
const temp = a(b(...args));
return temp;
};
});
}
const composedFunction = compose(f2, f3, f4, f5);
const result = composedFunction(2);
In the first reduce iteration the accumulator is f2 so we'll get f2(f3(2))=12. In the next iteration we'll call f4(12)=48. In the last iteration we'll call f5(48)=240. So the evaluation order is f5(f4(f2(f3(2)))). But using console.log I see that the evaluation order is f2(f3(f4(f5(2)))) which is also 240 by coincidence.
As far as I understand the function y is called for all array elements so why only the last function gets 2 as the parameter?
Let's step through the code with a very simple example:
compose(f2, f3, f4)
As no initial value was passed to reduce, it will start with the first (f2) and the second (f3) value of the array and call the callback with that, x gets called with a being f2 and b being f3. Now x does'nt do anything, it just returns function y that can access a and b through a closure.
Reduce will now continue to the third element, the first argument being the result of the previous callback (the closured y), and the second argument being f4. Now x gets called again, and another closure is created over y, y gets the finally returned from the whole function.
If we try to visualize thus closured function it'll be:
y { // closure of y
a -> y { // a references another closure of y
a -> f3,
b -> f2
},
b -> f4
}
Now you call that closured y and pass 2 into it, that will call b (f4) and pass the result to the call to a (closured y).
a ( b(...args))
y { ... } ( f4(2) )
Now that closured y will do the same:
a ( b ( ...args))
f2( f3( f4( 2 ) ) )
Hint: It is sometimes really difficult to keep track of closured values, therefore the console provides you with great utilities to keep track of them: Open your code in the consoles "debugger" tab, click on the line numbers where the function calls are to attach breakpoints, then run the code again, the execution will yield whenever a breakpoint is reached and you can see the values of all variables (including closured ones).
The reduce is not calling the functions f2, f3, f3, f5, but it is creating a function from those. This is the value of the accumulator in each iteration. Note that the value is a function and not a result from execution of the function.
1:a=f2;b=f3;return value(NOT TEMP but function y)=f2(f3(...args))
2:a(prev return value)=f2(f3(...args));b=f4;return value=f2(f3(f4(...args)))
and so on....
The compose function can be re-written as:
function compose(...funcs) {
return funcs.reduce(function (a, b) {
return function (arg) {
const temp = a(b(arg));
return temp;
};
});
}
After the first iteration, the returned function which is passed in as the next accumulator is:
function (arg) { // R1
return f2(f3(arg));
}
After the second iteration, the returned function which is passed in as the next accumulator is:
function (arg) { // R2
return R1(f4(arg));
}
And finally, the returned function assigned to composedFunction is:
function (arg) { // composedFunction
return R2(f5(arg));
}
So running composedFunction(2) and going back up the chain:
f5(2) returns 10
R2(10) returns R1(f4(10))
which is R1(40)
R1(40) returns f2(f3(40))
which is f2(120)
which is 240
Hopefully that's sufficient.
It can be written as a single call as:
function composedFunction(arg) {
return f2(f3(f4(f5(arg))));
}
I've just started to learn javascript and come across one task that I don't understand. Can anyone explain me why do we return function name "return f" in this example and what for do we use "f.toString"?
function sum(a) {
var currentSum = a;
function f(b) {
currentSum += b;
return f;
}
f.toString = function() {
return currentSum;
};
return f;
}
alert( sum(1)(2) ); // 3
alert( sum(5)(-1)(2) ); // 6
alert( sum(6)(-1)(-2)(-3) ); // 0
alert( sum(0)(1)(2)(3)(4)(5) ); // 15
Lets start with a simplified version:
function sum(currentSum) {
return function f(b) {
currentSum += b;
return f;
}
}
It willwork much like yours, you can do:
sum(1)(2)(3);//f
sum(1)(2);//f
However, they always return a function, so were not able to access the currentSum. Its in sums scope and as its never returned or passed, its impossible to get it. So we probably need another function we can call to get the current sum:
function sum(currentSum) {
function f(b) {
currentSum += b;
return f;
}
f.getSum = function() {
return currentSum;
};
return f;
}
So now f has a property (functions are objects too), which is a function called getSum to get our variable
sum(1)(2)(3)//f
sum(1)(2)(3).getSum()//6 <= wohhooo
But why do we call it toString ?
When adding a variable to a string, its converted to a string, e.g.
1+"one"//"1one"
the same applies to objects/functions, but in this case, the js parser tries to call their toString method first, so:
sum(1)(2)+"three"
equals
sum(1)(2).toString()+"three"
the same conversion happens when passing non strings to alert.
You are returning the object. So you can call the function again and, in the second call, you will have a currentSum allready.
when you do sum(3) the function will hold the number 3 and when you call it again doing sum(3)(4) it will add 4 to the currentSum.
then the alert will call the toString method and it will print the sum
look at the first example
alert( sum(1)(2) ); // 3
sum(1) // will return f. sum must return a function in order for the syntax to work
after it will return f it will become:
alert( f(2) );
With function sum you are passing the first argument a and returning function f which sum currentSum with the argument passed to f (b) and return again f and you can do that many times you want at the end it will call alert function which needs its first argument to be string. For that purpose you have rewritten the method on function f toString which in this case will return the currentSum.
Every object has a toString() method that is automatically called when the object is to be represented as a text value.
This is the task for understanding the type system of JavaScript. The task is to make function that adds numbers using currying. The idea is to make function that adds numbers when called like this sum(1)(2)(3), as you written in the task.
What do we do (looking to your code) in function sum:
1.
var currentSum = a;
Here you declare a sum variable in scope of function sum.
function f(b) {
currentSum += b;
return f;
}
Then you declare the function that will perform summation. It returns itself for possibility of doing such thing: f(1)(2)(3)
3.
f.toString = function() {
return currentSum;
};
After that you declare that f, converted to string returns sum value
Than you return f to start adding.
Than what about f.toString - it 's being called, when f is passed alert as an argument. That's automatic casting of javascript
I am trying to understand when should we use return, and when we shouldn't.
The returns used below are confusing to me. Please see the comments for my questions:
function each(collection, iterator) {
if (Array.isArray(collection)){
for (var i=0;i<collection.length;i++){
iterator(collection[i],i,collection)
}
}else {
for (var key in collection){
iterator(collection[key],key,collection)
}
}
};
function map(collection, iterator) {
var result = [];
// why we don't add "return" in front of the each() function here?
// why, if I add return, is the result "undefined"?
each(collection,function(value,key,collection){
result.push(iterator(value,key,collection));
})
return result;
};
function pluck(collection, key) {
// Why do we add "return" in front of map function, and
// why if I don't add it, the result is "undefined"?
return map(collection, function(item){
return item[key];
});
};
var car = [{type: "Fiat", model: "500", color: "white"}]
console.log(pluck(car,'type'));
Use return to have your function return a value; don't use it if the function doesn't need to return anything, or when you don't want to return yet.
In your example, if you just said:
function pluck(collection, key) {
map(collection, function(item){
return item[key];
});
};
map() would still be called, but the results of that map() would be discarded.
It's as though you'd written:
function add(a, b) {
var c = a + b; // computed, not returned
}
var result = add(1, 2); // undefined
instead of:
function add(a, b) {
var c = a + b; // computed
return c; // and returned
}
var result = add(1, 2); // 3
each() loops over a set of things, performing an action each time. It doesn't have a result to return.
And in your case, there's more code after the each() -- remember, return; ends the function from which it's returning.
// if we returned here
each(collection,function(value,key,collection){
// this isn't part of each's "value", it's just some code
// that runs within the each loop
result.push(iterator(value,key,collection));
})
// we'd never get here, to return the total result
return result;
Not exactly sure what your question is asking but I'm guessing you're comparing each versus map / pluck in the sense that each doesn't have an explicit return statement wheres map and pluck do have an explicit return statement.
A key point to note is that even though each doesn't have an explicit return statement, there is an implicit return undefined for every JavaScript function without an explicit return statement - which means that each also has an implicit return undefined.
The reason why each doesn't have a return statement is because you're NOT trying to return anything - instead, you're trying to do something to each item in a collection. For map and pluck, most libraries have defined it so that these functions are specified to return a collection.