Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Real world examples of using reduceRight in JavaScript

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:

  1. Lazy Evaluation (foldl is tail recursive, so how come foldr runs faster than foldl?)
  2. Short cut fusion using 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:

  1. What are some real world examples of using 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.
  2. Why is 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.

like image 551
Aadit M Shah Avatar asked Feb 19 '15 12:02

Aadit M Shah


People also ask

How to use reduceRight in JavaScript?

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.

What does reduceRight do?

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.

What is the difference between Reduce and reduceRight in JavaScript?

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.


2 Answers

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.

like image 139
Jamie Dixon Avatar answered Sep 17 '22 11:09

Jamie Dixon


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.

like image 43
Dan Burton Avatar answered Sep 20 '22 11:09

Dan Burton