5

我确信这是有充分理由的,但我没有看到。

Fold在(说)List回报

op在所有元素之间应用折叠运算符的结果和z

foldLeft它与做同样的事情但具有明确的顺序有明显的关系foldRight(因此不需要关联运算符)

FoldOption退货时

如果非空,则返回应用f到 thisscala.Option的值的结果。scala.Option否则,计算表达式ifEmpty

ifEmpty是(在)z列表的位置。 f是(在的位置)op

对于None(使用我的心智模型Option作为可能包含或不包含值的“容器”,是一个“空”容器),一切正常,Option.fold返回零(的值ifEmpty)。

Some(x)不过,for不应该f采用两个参数,z因此x它与 on 序列一致(包括与andfold具有相似的关系)。foldLeftfoldRight

肯定有一个反对这一点的实用论点 - 在实践中f只是x作为参数可能更方便。在大多数情况下,如果它确实也采取z了,那将被忽略。但一致性也很重要......

那么有人可以向我解释为什么foldOption 仍然是“正确的”fold吗?

4

2 回答 2

2

为什么应该这样?

fold “通常”采用二元运算符的原因是,“通常”用于可以使用二元运算符(和种子值 z)一一处理的列表。

Fold on an option 实际上是一个带有默认情况的 map 函数。如果你看它的定义,它的字面意思是:

if (isEmpty) ifEmpty else f(this.get)

由于您只有一个可能的参数,因此 f 必须是一元运算符。One could argue to have an option fold that takes a binary operator and used the ifEmpty value as the seed in case the option is defined, but your sensible seed value and your sensible value for when the option is empty may be greatly different.

正如有人指出的那样,对于不同的结构,您需要不同的参数(例如树),因为归约的“明智”应用具有不同的结构。

于 2014-10-22T15:04:41.360 回答
0

scala.Option.fold 是一个错误;糟糕的 API 设计。

Option {
  // This is equivalent to:  map f getOrElse ifEmpty.
  def fold[B](ifEmpty: => B)(f: A => B): B = if (isEmpty) ifEmpty else f(this.get)
}

Option.fold方法可能很方便,但它不是fold(同样适用于Either.fold)。

TraversableOnce {
  // List, et alia
  def fold[A1 >: A](z: A1)(op: (A1, A1) => A1): A1 = foldLeft(z)(op)
}

标准方法的好处是概念和类型签名是一致的(无需再次查看文档)。

此外,Option.foldLeft 一致的,并且确实采用二元运算符。

于 2014-10-24T20:47:43.270 回答