Codewars Solution - Functions acting on each other nested
It's a bit complicated. :-)
console.log(eight(minus(three())));
is run from the inside out, so let's follow it through:
three()
- callsmakeNum(3, undefined)
and returns what it returns.makeNum(3, undefined)
returns3
, so that's the return value.minus(3)
- callsminus
, passing in3
asright
.minus
returns a new function that closes overright
.eight(...)
- callsmakeNum(8, fnFromMinus)
wherefnFromMinus
is the function that was returned byminus(3)
.makeNum(8, fnFromMinus)
doesfnFromMinus
, passing in8
asleft
.fnFromMinus
returns the result ofleft - right
(remember thatright
is3
,fnFromMinus
closed over it).
Since 8 - 3
is 5
, the final result is 5
, which console.log
returns.
Here's an instrumented version:
let indent = 0;
function show(label) {
console.log(" ".repeat(indent * 4) + label);
}
function fname(fn) {
return fn ? fn.name : "undefined";
}
function makeNum(num, func) {
const descr = `makeNum(${num}, ${fname(func)})`;
show(descr);
++indent;
if (func === undefined) {
--indent;
show(`${descr} returns ${num}`);
return num;
} else {
const rv = func(num);
--indent;
show(`${descr} returns ${num}`);
return rv;
}
}
function three(func) {
const descr = `three(${fname(func)})`;
console.log(descr);
++indent;
const rv = makeNum(3, func);
--indent;
show(descr + ` returns ${rv}`);
return rv;
}
function eight(func) {
const descr = `eight(${fname(func)})`;
console.log(descr);
++indent;
const rv = makeNum(8, func);
--indent;
show(descr + ` returns ${rv}`);
return rv;
}
function minus(right) {
const fn = function fnFromMinus(left) {
show(`${fname(fn)} returns ${left} - ${right} = ${left - right}`);
return left - right;
};
try {
// For browsers that don't do `name` properly
fn.name = "fnFromMinus";
} catch (e) { }
show(`minus(${right}) returns ${fname(fn)}`);
return fn;
}
console.log(eight(minus(three()))); // will log out 5
.as-console-wrapper {
max-height: 100% !important;£
}
It's actually not that complicated if you work through it step by step. Let's work from the inside out. Calling:
three()
without a parameter means you're passing an undefined value as func. So it's the same as saying:
makeNum(3, undefined)
When makeNum sees that func is undefined, it returns num, which is 3.
So we've reduced this down to:
eight(minus(3))
Now let's see how
minus(3)
evaluates. minus sees that the parameter you've provided is 3, so it returns a function that can accept a "left" parameter and subtract the 3 that we've already provided from it. It does NOT execute. It just sits there, waiting to be called with a "left" parameter so it can subtract 3 from it.
So we've reduced this down to:
eight(function(left){
return left - 3;
})
Now let's see how this evaluates. eight is called with the func parameter being this function:
function(left){
return left - 3;
}
It then passes 8 and this function to makeNum when it says:
makeNum(8, func)
makeNum then sees that func has been provided (and is therefore not undefined) and returns func(num) back to the eight function, which is the same as passing:
8 - 3
back to the eight function. The eight function receives that value and then returns it. So we've reduced this down to:
5
which gets logged in the console.