When using the reduce method on an array of functions I am having difficulty tracing through how reduce works on the array exactly.
comboFunc(num, functionsArr) {
return functionsArr.reduce(function (last, current) {
return current(last);
}, input);
}
so with functionsArr = [add, multi]
and the functions add
and multi
being
function add(num) {
return num + 1;
}
and
function multi(num) {
return num * 30;
}
the function comboFunc
would:
comboFunc(2, functionsArr); //returns 90;
I understand how the reduce method works on an array of numbers folding the array into one value as it were, by applying a function to each element of the array. This example with comboFunc taking an array of functions as a parameter uses simple enough math that I can understand how reduce produces the value of 90 mathematically but I don't understand what is happening line by line and on each iteration from a functional level. I'm unable to articulate in my mind what exactly is happening when---how the input of 2 is getting passed from function to function vis-a-vis closure and the sequential firing off of each function, etc.
If the reduce method applies the function you pass in to each element of an array, and when each element in the array is a function...how can I write out for my own understanding syntactically how that looks?
The function passed into the reduce method returns current(last)
so that's a function returning a function. So that would make last
equal to the add
function and current
equal to multi
? In other words returning multi(add)
? If my logic is correct, this means what is happening is that the input then gets passed into add
and computed and then that returned value is passed into multi
and computed to ultimately return 90?
It looks like you're trying to create a composition function that takes an array of functions to apply to an input, num
Let's first cover a couple syntax errors. First you're missing the
function
keywordNext, you've named your parameter
num
but then you reference it asinput
in the function bodySo after you fix this, your function works, but what if we approach the problem a little differently?
To begin, I think we should go back to the basics of function composition.
I like picturing function composition as a little map.
In the example above, we could easily replace f with your
add
function, and g with yourmulti
function. Defining ? should also be fairly obvious now.(g∘f) can be said "g of f" and it just means apply x to f first, then apply that result to g.
Notice y isn't even present. We've defined h in terms of an x that gives us a direct "map" to a z, skipping over y entirely.
Composing two functions together is a very basic operation, and we could define a function to do that very easily
"Yeah, but I'm trying to work with N functions. Not just 2."
OK,
comp
works for two functions, but I've over simplified the problem. You're probably wondering how this would work if we wanted to compose 3, 4, or even more functions together.Well let's look at it again
Look very closely at the
∘
. We know this to be ourcomp
function and we can see it appear between each of our functions, a, b, c.Before we go further, let's say we have an array of numbers
If we want to sum the numbers, we would need to call
See how the
+
appears between each number? With our array of functions, it's no different!We just need to make that valid JavaScript. And it'll be easy too because we've already defined
∘
ascomp
.This calling of a function between terms in a list is called a linear fold and JavaScript has a function that does this called
reduce
.Alright, so let's put it use! We'll fold ("reduce") our list of functions using our
comp
functionOK, so it works for our original two functions, but let's make sure it works with an even longer list
"But why is this better?"
Just as we cut out
y
inh(x) = (g∘f)(x) = z
, notice how ourcompN
function doesn't concern itself withnum
,last
, orcurrent
. We've dropped 3 variables for our brain to think and it's much clearer what our function is doing.comp
takes f and g and composes them together to makeg ∘ f
.compN
callscomp
between each term in a list of functionsTo me, this is very straight forward and easy to understand. Just looking at the function bodies for each
comp
andcompN
, I can identify the intent immediately.It's no wonder you had difficulty trying to follow it.
comboFunc
was concerning itself with too much from the very onset because it's trying to be two operations instead of just one.So, I know I didn't step you through your original function, but I hope after reading this answer you have an even greater understanding of function composition and building your own functions with separated concerns.
EDIT
According to some discussion below, it would be valuable for our
compN
function to work on an empty array,[]
.Yuck! The intended behavior here will be for
compN
to create a function that returns an unmodified input.Using this as the starting point for the reduce will guarantee that our
compN
function will work even when an empty array is givenCheck it out
Now
compN
will work for an array of 0 or more functions.