How Array.reduce put functions as parameters in function composition? - javascript

Can somebody explain to me how Array.reduce can put functions as arguments in function composition like this:
const composeB = (f, g) => x => f(g(x))
const add = a => b => a + b
const add5 = add(5)
const double = a => a * 2
const add5ThenDouble = [double, add5].reduce(composeB)
console.log(add5ThenDouble(6)); // 22
So, according to my knowledge (which is not enough) of reduce function is that Array.reduce iterate through an array like this - it takes each of array values and puts them through callback function with another argument (lets call it accumulator). The next array value will undergo the same callback function, but with (eventually) changed accumulator value.
What confuses me in code example above is:
1) Array is list of functions [double, add5].
2) In first iteration, composeB will receive arguments: f=accumulator (empty value), g=double(function). ComposeB should return emptyvalue(double(6)) (or maybe not??)
I know that I am missing something, but can someone explain me what?

The documentation for reduce says that the first argument is
A function to execute on each element in the array (except for the first, if no initialValue is supplied).
So in this case, you have not supplied an initialValue and so compose is only called once (with arguments double and add5).

var inc = (x) => ++x, // increment +1
x2 = (x) => x*2, // multiply by 2
sq = (x) => x*x; // square
var compose = (f,g) => (_) => g(f(_));
var f1 = [ sq, inc, inc ].reduce(compose, (_) => _);
f1(10); // 102
var f2 = [ inc, sq, inc ].reduce(compose, (_) => _);
f2(10); // 122
See the code above, notice:
identity function (_) => _ as default value (second argument) for reduce
compose will NOT return a number, it will return a FUNCTION that is a composition of all the functions that were passed in before... So - only when you CALL the (say) f1, only then the functions will be executed.
we are putting all the functions from list [a,b,c,d,e] into a chain of e,d,c,b,a (reverse order!) and then execute as e(d(c(b(a(10))))) getting the order we actually wanted.
(f,g) => (_) => g(f(_)) <-- function arguments are actually reversed when calling them. Longer version: function compose (f, g) { return function (z) { return g(f(z)); }; }
p.s.: i use var because i can ;)

Related

What is the flow of execution with this compose function passed into Javascripts reduce?

I just want to know how reduce works in the case of code below(which was provided by a stackoverflow user in my previous question, i'm asking this question as his code snippet led to me having more questions that weren't cleared up and are too long to fit in a comment section). An array of functions is passed into a reducer. There is a compose function which runs on the array of functions. From my understanding of this f is the accumulator and g is the next item in the array. What is returned each cycle of the reduce becomes the accumulator for the next cycle. If there is no initalValue parameter passed into reduce then the first item in the array will be used as the initial accumulator value.
const compose = (f, g, i) => (...args) => {
console.log(i, g);
console.log(i, f);
return f(g(...args));
}
const f_xe = (x) => x + 'e',
f_xd = (x) => x + 'd',
f_xc = (x) => x + 'c',
f_xy = (x, y) => x + y;
console.log([f_xe, f_xd, f_xc, f_xy].reduce(compose)('a','b'));
// 3 [Function: f_xy]
// 3 [Function]
// 2 [Function: f_xc]
// 2 [Function]
// 1 [Function: f_xd]
// 1 [Function: f_xe]
// abcde
I visualize it like this:
cycle #1:
f = f_xe
g = f_xd
return f(g(...args))
^ which is f_xe(f_xd('a', 'b'))
cycle #2:
f = what was returned previously
^^ which will be f_xe(f_xd('a', 'b'))
g = f_xc
return f(g(...args))
^^ which is f_xe(f_xd('a', 'b'))(f_xc('a', 'b'))
I already know this line of thinking is wrong the way the flow works it works in an encapsulating manner, like so: f_xe(f_xd((f_xc(f_xy('a', 'b')))))
but why is this the case. If someone can intricately explain why it wraps this way and break down each cycle of the reduce step by step it would be immensely appreciated. Another thing I was wondering is, why doesn't f just try to evaluate immediately on the first cycle? f_xe(f_xd('a', 'b')) when this piece of code is returned wouldn't it try to evaluate that and produce an error instead of proceeding to the next item in the array? Instead the code starts evaluating from the last item in the array even though the compose function is instructed to be applied from the beginning. Which I do understand as with a composition function the last item will be ran first and then so on, however shouldn't the console log statements be ran in the order of first to last?
Again, I know my line of thinking is completely off with this one, but I was hoping if I shared my train of thought someone could push it in the right direction. Thank you to anyone who can shed some light on this.
Forget about the 'a' and 'b' arguments first. The important part is
const f = [f_xe, f_xd, f_xc, f_xy].reduce(compose);
This is what we need to look at, and where we can apply our definition of reduce for. The call of f('a','b') comes later.
When expanding the reduce call, we find
const f = compose(compose(compose(f_xe, f_xd, 1), f_xc, 2), f_xy, 3);
(This is a bit weird actually. I'd recommend using reduceRight for composing functions. Also pass the identify function as the initial value for the accumulator.)
Now we can expand the compose calls:
const f1 = (...args) => {
console.log(1, f_xe);
console.log(1, f_xd);
return f_xe(f_xd(...args));
}
const f2 = (...args) => {
console.log(2, f1);
console.log(2, f_xc);
return f1(f_xc(...args));
}
const f3 = (...args) => {
console.log(3, f2);
console.log(3, f_xy);
return f2(f_xy(...args));
}
const f = f3;
Now when you call f3('a', 'b'), you can see why the logs happen "backwards".
shouldn't the console log statements be ran in the order of first to last?
If you want that, you maybe better put them in the compose function and not in the closure that it returns. Try with
const compose = (f, g, i) => {
console.log(i, g);
console.log(i, f);
return (...args) => f(g(...args));
}

Javascript closure returning string instead of function

I am trying to write a simple compose function that takes a series of functions, and composes them like so:
compose(func1, func2, func3)(n) === func1(func2(func3(n)))
I do so by recursing through a rest parameter,
var compose = function(...args) {
return (n) => {
if (args.length) {
return args[0](compose(args.slice(1)));
} else {
return n;
}
};
};
I then attempt to compose a new function made up of a series of other functions,
var plusOneAndTwo = compose((n) => n + 1, (n) => n + 2);
plusOneAndTwo(1);
Instead of returning 4, I get back the body of the inner, anonymous function inside of compose as a string,
"(n) => {
if (args.length) {
return args[0](compose(args.slice(1)));
} else {
return n;
}
}1"
Note the "1" at the end of the string! I have no idea why this is happening, and in particular I'm perplexed by how a 1 is getting appended to the end of that.
Any clarification is appreciated, thanks!
The problem occurs in the recursive call to compose.
In particular, you are not passing the parameter n to it (as also suggested by others above). Furthermore, you need to expand the rest parameter in the call.
You should use something like:
return args[0](compose(...args.slice(1))(n))
In your case, you are simply returning:
return args[0](compose(args.slice(1)));
In your example you call compose((n) => n + 1, (n) => n + 2);. Compose then returns a function taking n as a parameter. In this function, args.length becomes 1 (i.e. true-is), args[0] becomes (n) => n + 1 and args.slice(1) becomes [(n) => n + 2].
Next, you call this returned function with the parameter n = 1. As args.length is 1, the if() statement will go into the if() case. In this if case, it will call args[0] with the argument compose(args.slice(1)).
In this recursive call, compose(args.slice(1)) is evaluated to a function, taking n as a parameter and the same function body.
This function is then given as the parameter n to args[0] (in the outer call). Recall that args[0] in this scenario is the function (n) => n + 1.
Thus the call as a whole is equivalent to:
// returned from the recursive call to compose(args.slice(1))
var n = (n) => {
if (args.length) {
return args[0](compose(args.slice(1)));
} else {
return n;
}
}
// applied to arg[0] == (n) => n + 1
return n + 1
This means that the code will attempt to add a function with the number 1.
In JavaScript adding a function and a number results in both objects coerced into a string. Casting a number into a string is trivial, casting a function into a string returns the function source code. These strings are then added to give the return value you saw: The function body as a string with the 1 at the end.
You just have to call the composed function:
return args[0](compose(...args.slice(1))(n));
Or without recursion it'll be:
const compose = (...fns) => start => fns.reduceRight((acc, fn) => fn(acc), start);
You could take a different approach by returning a new function or returning the last function for calling with arguments.
const
compose = (...fns) => fns.length
? v => compose(...fns.slice(0, -1))(fns.pop()(v))
: v => v,
fn1 = n => n * 5,
fn2 = n => n + 2,
fn3 = n => n * 7;
console.log(fn1(fn2(fn3(1))));
console.log(compose(fn1, fn2, fn3)(1));

JavaScript Arrow Function and Closure problem

I'm working on Lambda Expression in Javascript and I wrote the following code:
var succRender = (x) => 'succ('+ x + ')';
var numerify = expr => ((expr)(succRender) (0));
var ZERO = f => x => (x) ;
var ONE = f => x => (f(x));
var TWO = f => x => (f(f(x)));
var THREE = f => x => (f(f(f(x))));
var PLUS = n => m => f => z => (n(f) (m(f)(z))) ;
When I call:
console.log(numerify((PLUS) (TWO) (THREE)));
the console replies correctly
succ(succ(succ(succ(succ(0)))))
But I've called:
console.log(numerify((PLUS) (TWO) (THREE)));
and
var PLUS = n => m => f => z => (n(f) (m(f)(z))) ;
has four parameters....
How Javascript really works to perform this situation? Which are the "values" of f and z in the call? And how Javascript retrieves those value two complete the task?
thanks in advance
Ed
Lets evaluate it step by step:
PLUS(TWO)
that calls the first function and passes TWO as n, it evaluates to:
m => f => z => (n(f) (m(f)(z)))
Then that is called with (THREE), so m is THREE, it evaluates to:
f => z => (n(f) (m(f)(z)))
Now numerify(...) gets called with expr being the line above, and inside the function it is:
expr(succRender)(0)
So it calls the function with f being succRender and z being 0. Now we can evaluate the PLUS body, so this:
n(f) (m(f)(z))
becomes:
TWO(succRender) (THREE(succRender)(0))
Now the TWO call gets evaluated, with succRender being f and the line above results in
(x => (f(f(x)))) (THREE(succRender)(0))
The same happens with THREE:
(x => f(f(x)))) ((x => (f(f(f(x)))))(0))
Now the right arrow function gets evaluated as ut gets called with (0) so x is 0
(x => f(f(x))) (f(f(f(0))))
So now succRender (f) gets called three times with the redult of the previous call:
(x => f(f(x))) ("succ(succ(succ(0)))")
Now the last arrow function gets evaluated and succRender gets called two times again:
"succ(succ(succ(succ(succ(0)))))"
Let's unpack things a bit to see what is happening more clearly. I've re-written PLUS as a simpler function that still takes four parameters but just adds them together.
var PLUS = a => b => c => d => a + b + c + d;
var intermediateResult = (PLUS)(1)(2); //the parenthesis around PLUS are actually not needed
console.log("intermediateResult", intermediateResult);
var secondIntermediateResult = intermediateResult(3);
console.log("secondIntermediateResult", secondIntermediateResult);
var finalResult = intermediateResult(3)(4);
console.log("finalResult", finalResult);
As you can see, if you only pass the first two parameters, you get a function back. You need to "fill in" all values in order to get the result.
Now, let's break down what happens in your code:
(PLUS) (TWO) (THREE)
As I mentioned, the parenthesis around PLUS are not needed. They don't do anything. So I'll re-write what's happening here:
var firstIntermediateResult = PLUS(TWO);
var secondIntermediateResult = firstIntermediateResult(THREE);
So, you are passing the first two parameters.
numerify((PLUS) (TWO) (THREE))
If we substitute with the breakdown from before, this is equivalent to
numerify(secondIntermediateResult)
So, let's look at the numerify function:
var numerify = expr => ((expr)(succRender) (0));
it takes a parameter called expr, then passes succRender to it. This is another function but it doesn't matter in terms of understanding the call sequence. From above we see that will return another function that takes one final parameter before returning a result and that parameter is 0, so re-written the result of your program is:
var thirdIntermediateResult = secondIntermediateResult(succRender);
var finalResult = thirdIntermediateResult(0);
So, the final form of PLUS after all arguments are supplied looks like this
n(f) (m(f)(z)) --> TWO(succRender)(THREE(succRender)(0))

Currying function with unknown arguments in JavaScript

In a recent interview, I was asked to write a function that adds numbers and accepts parameters like this:
add(1)(2)(3) // result is 6
add(1,2)(3,4)(5) // result is 15
The number of parameters is not fixed, and the arguments can be either passed in sets or individually.
How can I implement this add function?
Given your examples, the number of parameters is fixed in some ways.
As #ASDFGerte pointed out, your examples seem to return the result after three invocations. In this case a simple implementation without introducing terms like variadic and currying could be
function add(...args1){
return function(...args2){
return function(...args3){
return args1.concat(args2).concat(args3).reduce((a,b)=>a+b)}}}
console.log(add(1)(2)(3))
console.log(add(1,2)(3,4)(5))
Every invocation accepts a variable number of parameters.
However it would be nice to generalize the construction of this nested functions structure and you can accomplish that with currying.
But if you want to allow an arbitrary number of invocations, when you should stop returning a new function and return the result? There is no way to know, and this is a simple, unaccurate and partial explanation to give you the idea of why they said you cannot accomplish what they asked you.
So the ultimate question is: is it possible that you misunderstood the question? Or maybe it was just a trick to test you
Edit
Another option would be to actually invoke the function when no arguments are passed in, change the call to add(1)(2)(3)()
Here an example recursive implementation
function sum (...args) {
let s = args.reduce((a,b)=>a+b)
return function (...x) {
return x.length == 0 ? s : sum(s, ...x)
};
}
console.log(sum(1,2)(2,3,4)(2)())
At every invocation computes the sum of current parameters and then return a new function that:
if is invoked without parameters just return the current sum
if other numbers are passed in, invokes recursively sum passing the actual sum and the new numbers
I'm a bit late to the party, but something like this would work (a bit hacky though in my opinion):
const add = (a, ...restA) => {
const fn = (b, ...restB) => {
return add([a, ...restA].reduce((x, y) => x + y) + [b, ...restB].reduce((x, y) => x + y))
};
fn.valueOf = () => {
return [a, ...restA].reduce((x, y) => x + y)
};
return fn;
}
This function returns a function with a value of the sum. The tests below are outputing the coerced values instead of the actual functions.
console.log(+add(1,2)(3,4)(5)); // 15
console.log(+add(1)) // 1
console.log(+add(1)(2)) // 3
console.log(+add(1)(2)(3)) // 6
console.log(+add(1)(2)(3)(4)) // 10
Since it's a currying function, it will always return another function so you can do something like this:
const addTwo = add(2);
console.log(+addTwo(5)); // 7
using reduce and spread it can be done as below
function calc(...args1){
return function (...args2){
return function (...args3){
let merge = [...args1, ...args2, ...args3]
return merge.reduce((x ,y)=> x + y) ;
}
}
}
let sum = calc(10)(1)(4);
console.log("sum",sum);
They probably wanted to know how comfortable you were with "javascript internals", such as how and when methods like Function#toString and Function#valueOf, Function#[Symbol.toPrimitive] are called under the hood.
const add = (...numbers) => {
const cadd = (...args) => add(...args, ...numbers);
cadd[Symbol.toPrimitive] = () => numbers.reduce((a, b) => a + b);
return cadd;
}
console.log(
`add(1,2)(3,4)(5) =>`, add(1,2)(3,4)(5),
); // result is 15
console.log(
`add(1,2) =>`, add(1,2),
); // result is 3
console.log(
`add(1,2)(5)(1,2)(5)(1,2)(5)(1,2)(5) =>`, add(1,2)(5)(1,2)(5)(1,2)(5)(1,2)(5),
); // result is 32

Using the same first argument in a Ramda pipe

Is it possible to compose the following function in Ramda?
(a, b) => R.pipe(func1(a), func2(a))(b)
The aim is passing argument a to all functions in the pipe.
My initial thought was the following:
R.pipe(R.juxt([func1, func2]), R.apply(R.pipe))
But this gives TypeError: Cannot read property 'length' of undefined.
This is easier to express using S.pipe as it takes an array of functions to compose.
One option is to use R.ap:
> S.pipe(R.ap([S.add, S.mult, S.add], [3]), 10)
42
Another option is to use R.map with S.T, the thrush combinator:
> S.pipe(R.map(S.T(3), [S.add, S.mult, S.add]), 10)
42
You could then wrap one of these in a lambda to create a binary function:
const f = (a, b) => S.pipe(R.ap([S.add, S.mult, S.add], [a]), b);
f(3, 10); // add(3)(mult(3)(add(3)(10)))
// => 42
You have to create a curried version of all the functions, then call the curried version of each with a and finally use b in either R.pipe or R.reduce
Let's say that the functions that need to have a as the first argument are f,g,h (in that specific order) then we want to achieve the following expression
h(a, g(a, f(a, b)))
First of all let's create a curried function which receives two arguments, a single value v and a function fn, when this function receives all its required arguments it will simply return fn(v)
const rev = R.curry((v, fn) => fn(v))
Next we can create the curried versions of the functions with R.map and R.curry
// note the reversed order of the functions
// I'll use R.compose instead of R.pipe
let curriedVersion = R.map(R.curry, [h,g,f])
However we also need to use a as the first argument of the curried functions, we could call each curried function with a using R.map but instead we will use our special function rev
const curriedVersion = R.map(R.compose(rev(a), R.curry), [h,g,f])
Finally let's use this array of curried functions with R.compose and b
const result = R.compose.apply(undefined, curriedVersion)(b)
One liner (for the functions f,g,h in that specific order):
const solver = (a, b) => R.compose.apply(undefined, R.map(R.compose(rev(a), R.curry), [h,g,f]))(b)
const add = (a, b) => a + b
const sub = (a, b) => a - b
const mul = (a, b) => a * b
const rev = R.curry((v, fn) => fn(v))
const solver = (a, b) => R.compose.apply(undefined, R.map(R.compose(rev(a), R.curry), [mul,sub,add]))(b)
// mul(2, sub(2, add(2, 3)))
// mul(2, sub(2, 5))
// mul(2, -3)
// -6
console.log(solver(2, 3))
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.21.0/ramda.min.js"></script>

Categories

Resources