web-dev-qa-db-ja.com

Scala:fold vs foldLeft

FoldとfoldLeftとそれぞれのreduceとreduceLeftがどのように機能するかを理解しようとしています。例としてfoldとfoldLeftを使用しました

scala> val r = List((ArrayBuffer(1, 2, 3, 4),10))
scala> r.foldLeft(ArrayBuffer(1,2,4,5))((x,y) => x -- y._1)

scala> res28: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(5)

scala> r.fold(ArrayBuffer(1,2,4,5))((x,y) => x -- y._1)
<console>:11: error: value _1 is not a member of Serializable with Equals
              r.fold(ArrayBuffer(1,2,4,5))((x,y) => x -- y._1)

なぜfoldfoldLeftとして機能しなかったのですか?とは Serializable with Equals? foldとfoldLeftには、パラメーターのジェネリック型に関してわずかに異なるAPIシグネチャがあることを理解しています。お知らせ下さい。ありがとう。

42
thlim

メソッドfold(元々並列計算用に追加された)は、適用可能な型の点でfoldLeftよりも強力ではありません。その署名は次のとおりです。

_def fold[A1 >: A](z: A1)(op: (A1, A1) => A1): A1
_

これは、折りたたみが行われる型は、コレクション要素型のスーパータイプでなければならないことを意味します。

_def foldLeft[B](z: B)(op: (B, A) => B): B
_

その理由は、foldを並列に実装できる一方で、foldLeftは並列に実装できないからです。これは、foldLeftが左から右に順番に進むことを意味する_*Left_部分だけでなく、演算子opが並列に計算された結果を結合できないためです。集約型Bを要素型Aと組み合わせる方法を定義しますが、B型の2つの集約を組み合わせる方法は定義しません。 foldメソッドは、これを定義します。これは、集約タイプ_A1_がエレメントタイプAのスーパータイプ、つまり_A1 >: A_である必要があるためです。このスーパータイプの関係により、集約と要素を同時に折りたたみ、集約を組み合わせることができます(両方とも単一の演算子を使用)。

ただし、集計と要素タイプのこのスーパータイプの関係は、例の集計タイプ_A1_が_(ArrayBuffer[Int], Int)_のスーパータイプであることも意味します。集計のゼロ要素は_ArrayBuffer[Int]_型のArrayBuffer(1, 2, 4, 5)であるため、集計型はこれらの両方のスーパータイプであると推測されます-そしてそれは_Serializable with Equals_タプルと配列バッファーの上限。

一般に、任意の型の並列フォールディングを許可する場合(順不同で行われます)、2つの集計の結合方法を定義する必要があるaggregateメソッドを使用する必要があります。あなたの場合:

_r.aggregate(ArrayBuffer(1, 2, 4, 5))({ (x, y) => x -- y._1 }, (x, y) => x intersect y)
_

ところで、reduce/reduceLeftを使用して例を書いてみてください-要素タイプとこれら両方のメソッドが持つ集約タイプとのスーパータイプの関係のため、同様の結果につながることがわかります。あなたが説明したようなエラー。

64
axel22