0

Reduce can be an override fold that doesn't take the first element. I guess there is an answer to that design decision but I can't find it.

1
  • To be honest reduce is mostly useless compared with foldLeft I don't think I have used it in years. Commented May 7, 2022 at 2:53

2 Answers 2

3

The two operations are fundamentally different. Giving them the same name would be confusing. In Ruby, the equivalent method is called Enumerable#inject (aliased to Enumerable#reduce) and is overloaded to act like both Scala's scala.collection.Iterable.foldLeft[B](z: B)(op: (B, A) => B): B and scala.collection.Iterable.reduceLeft[B >: A](op: (B, A) => B): B. And you can see the confusion this causes in .

[Note: From here on, I will use Scala terminology to refer to the two different operations, i.e. fold and reduce.]

Some of the differences between the two operations are:

  • fold works with an empty collection, reduce doesn't. In Scala, it will either throw an UnsupportedOperationException or you can use scala.collection.Iterable.reduceLeftOption[B >: A](op: (B, A) => B): Option[B]. In Haskell, what Scala calls reduceLeft is called Data.List.foldl1 :: Foldable t => (a -> a -> a) -> t a -> a for that reason: because you need at least 1 element.
  • With reduce, the result type is the same as the element type (or more precisely, a supertype of the element type), whereas with fold, the result type can be anything. For example, you cannot sum the lengths of a collection of strings with reduce because the result type of reduce on a collection of strings cannot be a number, it must be string.
  • The most important one: fold is a general iteration operation, meaning, everything you can do with a loop or with recursion, you can do with a fold. If you have fold, you don't need map, you don't need filter, you don't need forall, you don't need groupBy, you don't need scan, and so on, and of course you also don't need reduce. You can implement all of them using fold. (I did that for Ruby once.) reduce is not general, and you can't e.g. implement any collection transformation (e.g. map or filter or even just reverse) because the result type of reduce is the element type and cannot be the collection type.

Because those two operations are so different, it just makes sense to give them different names: fold and reduce in Scala, foldX and foldX1 in Haskell, etc. In the language I am most familiar with, Ruby, they have the same name, and that has led to confusion.

Sign up to request clarification or add additional context in comments.

1 Comment

foldX1 really adds so much clarity ... :D
1

In short, they have different type constraints, and therefore different type signatures. The result of a fold can be anything you want. The result of a reduce must be a supertype of the elements.

This is why fold and reduce are usually combined in dynamically-typed languages, but separated in statically-typed languages.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.