Suggestion: remove your `reduce` and `fold`

This is an old, old point, that’s worth repeating every now and then.

I’ve been cleaning our doc site recently and submitted a PR that’s a good show case on comparing the readability, perf and “entropy-ness” of reduce/fold vs various substitutes.

It probably doesn’t come as a surprise that there’s no good real-world usage of reduce. Even the reduce examples that look clean are usually from a contortion of the callback to fit that api style, or from solutions in search of problems.

Go in your codebase, spot those reduces and see if you can remove them like I did in the PR. You’ll probably find equal amount of wins!

6 Likes

Love this one. Remove most reduces by chenglou · Pull Request #366 · rescript-association/rescript-lang.org · GitHub

From:

var match = Belt_Array.reduce(BlogApi.getAllPosts(undefined), [
        [],
        []
      ], (function (acc, postData) {
          var archived = acc[1];
          var posts = acc[0];
          if (postData.archived) {
            archived.push(postData);
          } else {
            posts.push(postData);
          }
          return [
                  posts,
                  archived
                ];

To:

  var match = Belt_Array.partition(BlogApi.getAllPosts(undefined), (function (data) {
          return data.archived;
        }));
2 Likes

Reminds me of the “No Raw Loops” part of this Sean Parent’s talk: GoingNative 2013 C++ Seasoning - YouTube

1 Like

I agree with your points but I have a caveat on the last one:

  • If you’re reducing to another collection: use recursion. Even recursion is more readable than reduce.

There are data structures where fold ends up cleaner, particularly if it’s used a lot. Building a recursive loop becomes tiresome. It’s rare, but it does come up.

1 Like

I use reduce pretty often in my JavaScript code, I’m sure there are alternatives and in some cases, those alternatives could be more readable but I think it will be a problem for some JS developers

1 Like

The background is that folds are universal. That is, almost any reduction of a data structure (not just lists or arrays) to a singular element can be written as a fold of a specific reducer-function. So if we have a specific function, like partition, we can find an f such that partition = fold(f, ...).

As a general rule, if you have a more specific function, it’s usually better to use it than to write down a Swiss Army Knife fold.

But people don’t always know the existence of a specific function. Hence, because of the universality of the fold, they pick the fold to solve the problem.

Universality is also a powerful tool. If you have a fold, you automatically also have a partition function over the data structure with no extra work. This gives you freedom over the data structure choice, as long as it is amenable to folds. By writing all of your code as variants of fold (or reduce), you provide proof that your program is independent of data structure, which can be a good property to have in some cases.

8 Likes