Home > Blockchain >  There is any objective reason why Scala differentiate fold and reduce functions?
There is any objective reason why Scala differentiate fold and reduce functions?

Time:05-08

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.

CodePudding user response:

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, 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 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.

CodePudding user response:

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.

  • Related