Scala 区分 fold 和 reduce 函数有什么 objective 原因吗?

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

Reduce 可以是不采用第一个元素的覆盖折叠。 我想这个设计决定有答案,但我找不到。

这两个操作是根本不同的。给他们同一个名字会造成混淆。在 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 .

[注意:从这里开始,我将使用 Scala 术语来指代两个不同的操作,即 foldreduce。]

这两个操作之间的一些区别是:

  • fold 适用于空集合,reduce 不适用。在 Scala 中,它会因为这个原因抛出一个 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:因为你至少需要 1 个元素。
  • 对于reduce,结果类型与元素类型相同(或者更准确地说,是元素类型的超类型),而对于fold,结果类型可以是anything。例如,不能用 reduce 对字符串集合的长度求和,因为字符串集合上 reduce 的结果类型不能是数字,它必须是字符串。
  • 最重要的一个:fold是一个一般迭代操作,意思是,你可以用循环或递归做的一切,你可以用 fold 来做。如果你有fold,你不需要map,你不需要filter,你不需要forall,你不需要[=32] =],你不需要scan,等等,当然你也不需要reduce。您可以使用 fold 实现所有这些。 (I did that for Ruby once.) reduce 不是 通用的,你不能实施 any 集合转换(例如 mapfilter 甚至只是 reverse)因为 reduce 的结果类型是元素类型并且不能是集合类型。

因为这两个操作是如此不同,所以给它们不同的名字是有意义的:在 Scala 中 foldreducefoldXfoldX1 在 Haskell,等等。在我最熟悉的语言中,Ruby,它们具有相同的名称,因此导致混淆。

简而言之,它们具有不同的类型约束,因此具有不同的类型签名。 fold 的结果可以是任何你想要的。 reduce 的结果必须是元素的超类型。

这就是为什么 foldreduce 通常在 dynamically-typed 种语言中合并,但在 statically-typed 种语言中分开。