Разница между складками и foldLeft или foldRight?

ПРИМЕЧАНИЕ. Я нахожусь в Scala 2.8-can, что может быть проблемой?

Почему я не могу использовать функцию fold так же, как foldLeft или foldRight?

В Set scaladoc говорится, что:

Результат сгибания может быть только супертипом этого параметра типа параллельной коллекции T.

Но я не вижу параметра типа T в сигнатуре функции:

def fold [A1 >: A] (z: A1)(op: (A1, A1) ⇒ A1): A1

В чем разница между foldLeft-Right и fold, и как использовать последнюю?

EDIT: Например, как бы я написал сводку, чтобы добавить все элементы в список? С foldLeft это будет:

val foo = List(1, 2, 3)
foo.foldLeft(0)(_ + _)

// now try fold:
foo.fold(0)(_ + _)
>:7: error: value fold is not a member of List[Int]
  foo.fold(0)(_ + _)
    ^

Ответ 1

Вы правы, когда старая версия Scala является проблемой. Если вы посмотрите страницу scaladoc для Scala 2.8.1, вы увидите, что там не определено фолд (что согласуется с вашим сообщением об ошибке). По-видимому, fold было введено в Scala 2.9.

Ответ 2

Короткий ответ:

foldRight связывается вправо. То есть элементы будут накапливаться в порядке справа налево:

List(a,b,c).foldRight(z)(f) = f(a, f(b, f(c, z)))

foldLeft связывается влево. То есть аккумулятор будет инициализирован, и элементы будут добавлены к аккумулятору в порядке слева направо:

List(a,b,c).foldLeft(z)(f) = f(f(f(z, a), b), c)

fold ассоциативен тем, что порядок, в котором элементы складываются вместе, не определен. То есть аргументы fold образуют monoid.

Ответ 3

fold, в отличие от foldRight и foldLeft, не дает никаких гарантий относительно порядка, в котором будут обрабатываться элементы коллекции. Вероятно, вы захотите использовать fold с его более ограниченной подписью с параллельными коллекциями, где отсутствие гарантированного порядка обработки помогает параллельной коллекции реализовать сворачивание параллельно. Причина изменения подписи схожа: с дополнительными ограничениями проще сделать параллельную складку.

Ответ 4

В вашем конкретном примере вы будете кодировать его так же, как и с foldLeft.

val ns = List(1, 2, 3, 4)
val s0 = ns.foldLeft (0) (_+_) //10
val s1 = ns.fold (0) (_+_) //10
assert(s0 == s1)

Ответ 5

Согласитесь с другими ответами. подумал о том, чтобы дать простой иллюстративный пример:

 object MyClass {
 def main(args: Array[String]) {
val numbers = List(5, 4, 8, 6, 2)
 val a =  numbers.fold(0) { (z, i) =>
 {
     println("fold val1 " + z +" val2 " + i)
  z + i

 }
}
println(a)
 val b =  numbers.foldLeft(0) { (z, i) =>
 println("foldleft val1 " + z +" val2 " + i)
  z + i

}
println(b)
   val c =  numbers.foldRight(0) { (z, i) =>
   println("fold right val1 " + z +" val2 " + i)
  z + i

}
println(c)
 }
}

Результат сам по себе поясняет:

fold val1 0 val2 5
fold val1 5 val2 4
fold val1 9 val2 8
fold val1 17 val2 6
fold val1 23 val2 2
25
foldleft val1 0 val2 5
foldleft val1 5 val2 4
foldleft val1 9 val2 8
foldleft val1 17 val2 6
foldleft val1 23 val2 2
25
fold right val1 2 val2 0
fold right val1 6 val2 2
fold right val1 8 val2 8
fold right val1 4 val2 16
fold right val1 5 val2 20
25

Ответ 6

fold() выполняет параллельную обработку, поэтому не гарантирует порядок обработки. где как foldLeft и foldRight обрабатывают элементы последовательно слева направо (в случае foldLeft) или справа налево (в случае foldRight)

Примеры суммирования списка -

val numList = List(1, 2, 3, 4, 5)

val r1 = numList.par.fold(0)((acc, value) => {
  println("adding accumulator=" + acc + ", value=" + value + " => " + (acc + value))
  acc + value
})
println("fold(): " + r1)
println("#######################")
/*
 * You can see from the output that,
 * fold process the elements of parallel collection in parallel
 * So it is parallel not linear operation.
 * 
 * adding accumulator=0, value=4 => 4
 * adding accumulator=0, value=3 => 3
 * adding accumulator=0, value=1 => 1
 * adding accumulator=0, value=5 => 5
 * adding accumulator=4, value=5 => 9
 * adding accumulator=0, value=2 => 2
 * adding accumulator=3, value=9 => 12
 * adding accumulator=1, value=2 => 3
 * adding accumulator=3, value=12 => 15
 * fold(): 15
 */

val r2 = numList.par.foldLeft(0)((acc, value) => {
  println("adding accumulator=" + acc + ", value=" + value + " => " + (acc + value))
  acc + value
})
println("foldLeft(): " + r2)
println("#######################")
/*
 * You can see that foldLeft
 * picks elements from left to right.
 * It means foldLeft does sequence operation
 * 
 * adding accumulator=0, value=1 => 1
 * adding accumulator=1, value=2 => 3
 * adding accumulator=3, value=3 => 6
 * adding accumulator=6, value=4 => 10
 * adding accumulator=10, value=5 => 15
 * foldLeft(): 15
 * #######################
 */

// --> Note in foldRight second arguments is accumulated one.
val r3 = numList.par.foldRight(0)((value, acc) => {
 println("adding value=" + value + ", acc=" + acc + " => " + (value + acc))
  acc + value
})
println("foldRight(): " + r3)
println("#######################")

/*
 * You can see that foldRight
 * picks elements from right to left.
 * It means foldRight does sequence operation.
 * 
 * adding value=5, acc=0 => 5
 * adding value=4, acc=5 => 9
 * adding value=3, acc=9 => 12
 * adding value=2, acc=12 => 14
 * adding value=1, acc=14 => 15
 * foldRight(): 15
 * #######################
 */