I am not sure what is the difference between fold
and foldLeft
in Scala.
The question Difference between fold and foldLeft or foldRight? has an
The error. You are getting a compile-time error because the signature of fold
only allows folding values of type which is the supertype of the type of the values in the collection, and the only supertype of String
(your collection type) and Int
(the type of your provided zero element) is Any
. So, the type of the fold result is inferred to be Any
- and Any
does not have a method toInt
.
Note that the two versions of fold
have different signatures:
fold[A1 >: A](z: A1)(op: (A1, A1) => A1): A1
foldLeft[B](z: B)(f: (B, A) => B): B
Why do they have different signatures? This is because fold
could be implemented in parallel, as is the case with parallel collections. When multiple processors fold over the values in the collections, each one of the processors takes a subset of elements of type A
and produces the folded value of type A1
, by consecutively applying op
. The results produced by those processors must be combined together into a final folding value - this is done using the op
function, which does exactly that.
Now, note that this cannot be done using the f
in foldLeft
, because each of the processors produces a folded value of type B
. Several values of type B
cannot be combined using f
, because f
only combines value B
with another value of type A
- there is no correspondance between types A
and B
.
Example. In your example, assume the 1st processor takes elements "1", "2"
and the 2nd takes element "3"
. The first one will produce the folded value 3
, and the second will produce another folded value 3
. Now they have to combine their results to get the final folded value - this is impossible, because the closure _ + _.toInt
only knows how to combine an Int
and String
, and not 2 Int
values.
For situations where these types differ, use aggregate
, in which you have to define how to combine two values of type B
:
def aggregate[B](z: B)(seqop: (B, A) => B, combop: (B, B) => B): B
The combop
above defines how to do the final step when the fold result and the elements in the collection have different types.
The neutral element. As described above, multiple processors may fold over subsets of elements in the collection. Each one of them will start its folded value by adding the neutral element.
In the following example:
List(1, 2, 3).foldLeft(4)(_ + _)
always returns 10 = 4 + 1 + 2 + 3
.
However, 4
should not be used with fold
, as it is not a neutral element:
List(1, 2, 3).fold(4)(_ + _)
The above may return (4 + 1 + 2) + (4 + 3) = 14
or (4 + 1) + (4 + 2) + (4 + 3) = 18
. If you don't use the neutral element for the fold
, the results are nondeterministic. In the same way, you can use the Nil
as a neutral element, but not a non-empty list.