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 ruby.
[注意:从这里开始,我将使用 Scala 术语来指代两个不同的操作,即 fold
和 reduce
。]
这两个操作之间的一些区别是:
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 集合转换(例如 map
或 filter
甚至只是 reverse
)因为 reduce
的结果类型是元素类型并且不能是集合类型。
因为这两个操作是如此不同,所以给它们不同的名字是有意义的:在 Scala 中 fold
和 reduce
,foldX
和 foldX1
在 Haskell,等等。在我最熟悉的语言中,Ruby,它们具有相同的名称,因此导致混淆。
简而言之,它们具有不同的类型约束,因此具有不同的类型签名。 fold
的结果可以是任何你想要的。 reduce
的结果必须是元素的超类型。
这就是为什么 fold
和 reduce
通常在 dynamically-typed 种语言中合并,但在 statically-typed 种语言中分开。
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 ruby.
[注意:从这里开始,我将使用 Scala 术语来指代两个不同的操作,即 fold
和 reduce
。]
这两个操作之间的一些区别是:
fold
适用于空集合,reduce
不适用。在 Scala 中,它会因为这个原因抛出一个UnsupportedOperationException
or you can usescala.collection.Iterable.reduceLeftOption[B >: A](op: (B, A) => B): Option[B]
. In Haskell, what Scala callsreduceLeft
is calledData.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 集合转换(例如map
或filter
甚至只是reverse
)因为reduce
的结果类型是元素类型并且不能是集合类型。
因为这两个操作是如此不同,所以给它们不同的名字是有意义的:在 Scala 中 fold
和 reduce
,foldX
和 foldX1
在 Haskell,等等。在我最熟悉的语言中,Ruby,它们具有相同的名称,因此导致混淆。
简而言之,它们具有不同的类型约束,因此具有不同的类型签名。 fold
的结果可以是任何你想要的。 reduce
的结果必须是元素的超类型。
这就是为什么 fold
和 reduce
通常在 dynamically-typed 种语言中合并,但在 statically-typed 种语言中分开。