I am trying to understand how fold and foldLeft and the respective reduce and reduceLeft work. I used fold and foldLeft as my example
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)
Why fold
didn't work as foldLeft
? What is Serializable with Equals
? I understand fold and foldLeft has slight different API signature in terms of parameter generic types. Please advise. Thanks.
Best Answer
The method
fold
(originally added for parallel computation) is less powerful thanfoldLeft
in terms of types it can be applied to. Its signature is:This means that the type over which the folding is done has to be a supertype of the collection element type.
The reason is that
fold
can be implemented in parallel, whilefoldLeft
cannot. This is not only because of the*Left
part which implies thatfoldLeft
goes from left to right sequentially, but also because the operatorop
cannot combine results computed in parallel -- it only defines how to combine the aggregation typeB
with the element typeA
, but not how to combine two aggregations of typeB
. Thefold
method, in turn, does define this, because the aggregation typeA1
has to be a supertype of the element typeA
, that isA1 >: A
. This supertype relationship allows in the same time folding over the aggregation and elements, and combining aggregations -- both with a single operator.But, this supertype relationship between the aggregation and the element type also means that the aggregation type
A1
in your example should be the supertype of(ArrayBuffer[Int], Int)
. Since the zero element of your aggregation isArrayBuffer(1, 2, 4, 5)
of the typeArrayBuffer[Int]
, the aggregation type is inferred to be the supertype of both of these -- and that'sSerializable with Equals
, the only least upper bound of a tuple and an array buffer.In general, if you want to allow parallel folding for arbitrary types (which is done out of order) you have to use the method
aggregate
which requires defining how two aggregations are combined. In your case:Btw, try writing your example with
reduce
/reduceLeft
-- because of the supertype relationship between the element type and the aggregation type that both these methods have, you will find that it leads to a similar error as the one you've described.