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.
2 Answers
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 ruby.
[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:
foldworks with an empty collection,reducedoesn't. In Scala, it will either throw anUnsupportedOperationExceptionor you can usescala.collection.Iterable.reduceLeftOption[B >: A](op: (B, A) => B): Option[B]. In Haskell, what Scala callsreduceLeftis calledData.List.foldl1 :: Foldable t => (a -> a -> a) -> t a -> afor 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 withfold, the result type can be anything. For example, you cannot sum the lengths of a collection of strings withreducebecause the result type ofreduceon a collection of strings cannot be a number, it must be string. - The most important one:
foldis a general iteration operation, meaning, everything you can do with a loop or with recursion, you can do with afold. If you havefold, you don't needmap, you don't needfilter, you don't needforall, you don't needgroupBy, you don't needscan, and so on, and of course you also don't needreduce. You can implement all of them usingfold. (I did that for Ruby once.)reduceis not general, and you can't e.g. implement any collection transformation (e.g.maporfilteror even justreverse) because the result type ofreduceis 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.
1 Comment
foldX1 really adds so much clarity ... :DIn 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.
reduceis mostly useless compared withfoldLeftI don't think I have used it in years.