A while ago, I posted a question on StackOverflow showing that the native implementation of reduceRight
in JavaScript is annoying. Hence, I created a Haskell-style foldr
function as a remedy:
function foldr(array, callback, initial) {
var length = array.length;
if (arguments.length < 3) {
if (length > 0) var result = array[--length];
else throw new Error("Reduce of empty array with no initial value");
} else var result = initial;
while (length > 0) {
var index = --length;
result = callback(array[index], result, index, array);
}
return result;
}
However, I never used this foldr
function simply because I never needed to iterate over an array from right-to-left. This got me thinking, why don't I use foldr
in JavaScript as much as I do in Haskell and what are some real world examples of using foldr
in JavaScript?
I could be wrong, but I believe that the foldr
function is used widely in Haskell because of:
foldr
/build
(Correctness of short cut fusion: foldr
/build
)This would explain why foldr
or reduceRight
are not widely used in JavaScript. I have yet to see a real world use of foldr
only for its right-to-left iteration order.
This brings me to my two questions:
reduceRight
in JavaScript? Perhaps you have used it in an npm package. It would be great if you could link me to your code and explain why you needed to use reduceRight
instead of reduce
.reduceRight
not used as widely as reduce
is in JavaScript? I already provided my two cents on this matter. I believe that foldr
is primarily used only for its laziness, which is why reduceRight
is not very useful in JavaScript. However, I could be wrong.For the first question, I tried to find some real world examples for using reduceRight
in JavaScript. However, I didn't find any satisfactory answers. The only examples I found were trivial and theoretical:
when to use reduce and reduceRight?
What I am looking for is a practical example. When is it practical to use reduceRight
in JavaScript instead of reduce
?
For the second question, I understand that it is primarily opinion based which is why it's alright if you don't answer it. The main focus of this post is on the first question, not the second.
JavaScript Array reduceRight()The reduceRight() method executes a reducer function for each array element. The reduceRight() method works from right to left. The reduceRight() method returns a single value: the function's accumulated result. The reduceRight() method does not execute the function for empty elements.
reduceRight() The reduceRight() method applies a function against an accumulator and each value of the array (from right-to-left) to reduce it to a single value.
The only difference between reduce and reduceRight is the direction of the iteration. reduce iterates over the array elements left to right. And reduceRight iterates over the elements right to left.
To answer your first question, reduceRight
comes in pretty handy when you want to specify items in a left-to-right manner but execute them in a right-to-left manner.
Consider this naive implementation of a compose function that takes arguments left-to-right but is read and executed right-to-left:
var compose = function () {
var args = [].slice.call(arguments);
return function (initial) {
return args.reduceRight(function (prev, next) {
return next(prev);
}, initial);
}
}
Rather than take up time/space with a call to reverse
on the array, it's simpler and easier to make sense of a reduceRight
call.
An example of using this compose
function would looks something like:
var square = function (input) {
return input * input;
};
var add5 = function (input) {
return input + 5;
};
var log = function (input) {
console.log(input);
};
var result = compose(log, square, add5)(1); // -> 36
I'm certain there are many more technical examples of reduceRight
being useful and this is just one.
You are absolutely correct, to the point where I'm not entirely sure this is even a real question. Laziness and fusion are both huge reasons why foldr
is preferred in Haskell. Both of these things are absent in JavaScript's arrays, so there is literally no reason to use reduceRight in real world JavaScript. I mean, you could contrive a case where you've constructed an array by pushing things onto the end, and then you want to iterate over them from newest to oldest while accumulating a result. But imo that's very contrived.
Just to illustrate the Haskell side of things. Note that in Haskell, a right fold does not actually perform evaluation from right to left. You can think about grouping evaluation from right to left, but due to laziness, that's not what is computed. Consider:
foldr (\a _ -> Just a) undefined [1..]
I've supplied an undefined
starting value for the accumulator, and the infinite list of natural numbers to fold over. Oh dear. Yet this matters not one bit. This expression happily evaluates to Just 1
.
Conceptually, the grouping works like this:
let step a _ = Just a
let foldTheRest = foldr step undefined [2..]
step 1 foldTheRest
Thinking about the grouping, we "fold the rest", then we apply the step
function to two arguments: the "first element of the list", and "whatever we got from folding the rest of the list." However, since the stepping function doesn't even need it's accumulator argument, that part of the computation is never evaluated. All we needed to evaluate this particular fold was the "first element of the list."
To reiterate, JavaScript arrays retain none of the benefits of foldr
that Haskell enjoys, so there is literally no reason to use reduceRight
. (In contrast, there are sometimes good reasons in Haskell to use a strict left fold.)
n.b. I disagree with your other question where you conclude that "the native implementation of reduceRight is wrong." I agree that it's annoying that they have chosen the argument order that they did, but it's not inherently wrong.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With