web-dev-qa-db-fra.com

Différence entre fold et foldLeft ou foldRight?

REMARQUE: je suis sur Scala 2.8 - cela peut-il être un problème?

Pourquoi ne puis-je pas utiliser la fonction fold de la même manière que foldLeft ou foldRight?

Dans le Set scaladoc il dit que:

Le résultat du pliage ne peut être qu'un super-type du paramètre de type de cette collection parallèle T.

Mais je ne vois aucun paramètre de type T dans la signature de la fonction:

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

Quelle est la différence entre le foldLeft-Right et fold, et comment utiliser ce dernier?

EDIT: Par exemple, comment pourrais-je écrire un pli pour ajouter tous les éléments dans une liste? Avec foldLeft ce serait:

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)(_ + _)
    ^
63
Andriy Drozdyuk

Vous avez raison sur l'ancienne version de Scala étant un problème. Si vous regardez la page scaladoc pour Scala 2.8. 1, vous ne verrez aucun pli défini ici (ce qui est cohérent avec votre message d'erreur). Apparemment, fold a été introduit dans Scala 2.9.

8
exlevan

Réponse courte:

foldRight s'associe à droite. C'est à dire. les éléments seront accumulés de droite à gauche:

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

foldLeft s'associe à gauche. C'est à dire. un accumulateur sera initialisé et des éléments seront ajoutés à l'accumulateur de gauche à droite:

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

fold est associatif en ce que l'ordre dans lequel les éléments sont additionnés n'est pas défini. C'est à dire. les arguments de fold forment un monoïde.

68
Apocalisp

fold, contrairement à foldRight et foldLeft, n'offre aucune garantie quant à l'ordre dans lequel les éléments de la collection seront traités. Vous voudrez probablement utiliser fold, avec sa signature plus contrainte, avec des collections parallèles, où le manque d'ordre de traitement garanti aide la collection parallèle à implémenter le pliage de manière parallèle. La raison du changement de signature est similaire: avec les contraintes supplémentaires, il est plus facile de faire un pli parallèle.

54

D'accord avec d'autres réponses. pensé à donner un exemple illustratif simple:

 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)
 }
}

Le résultat est explicite:

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
3
Ram Ghadiyaram

Pour votre exemple particulier, vous le coderiez de la même manière que vous le feriez avec foldLeft.

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