web-dev-qa-db-fra.com

Scala: fold vs foldLeft

J'essaie de comprendre comment se déroulent fold and foldLeft et la réduction et la réduction de gauche respectives. J'ai utilisé fold and foldLeft comme exemple

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)

Pourquoi fold ne fonctionnait pas comme foldLeft? Quel est Serializable with Equals? Je comprends que fold et foldLeft ont une signature API légèrement différente en termes de types de paramètres génériques. S'il vous plaît donnez votre avis. Merci.

42
thlim

La méthode fold (ajoutée à l'origine pour le calcul parallèle) est moins puissante que foldLeft en termes de types auxquels elle peut être appliquée. Sa signature est:

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

Cela signifie que le type sur lequel le pliage est effectué doit être un supertype du type d'élément de collection.

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

La raison en est que fold peut être implémenté en parallèle, tandis que foldLeft ne peut pas. Ce n'est pas seulement à cause de la partie *Left Qui implique que foldLeft va de gauche à droite séquentiellement, mais aussi parce que l'opérateur op ne peut pas combiner des résultats calculés en parallèle - il définit uniquement comment combiner le type d'agrégation B avec le type d'élément A, mais pas comment combiner deux agrégations de type B. La méthode fold, à son tour, définit cela, car le type d'agrégation A1 Doit être un supertype du type d'élément A, c'est-à-dire A1 >: A . Cette relation de supertype permet en même temps de replier l'agrégation et les éléments, et de combiner les agrégations - les deux avec un seul opérateur.

Mais, cette relation de supertype entre l'agrégation et le type d'élément signifie également que le type d'agrégation A1 Dans votre exemple doit être le supertype de (ArrayBuffer[Int], Int). Puisque l'élément zéro de votre agrégation est ArrayBuffer(1, 2, 4, 5) du type ArrayBuffer[Int], Le type d'agrégation est supposé être le super-type de ces deux - et c'est Serializable with Equals, Le seule limite supérieure d'un Tuple et d'un tampon de tableau.

En général, si vous souhaitez autoriser le pliage parallèle pour les types arbitraires (ce qui est fait dans le désordre), vous devez utiliser la méthode aggregate qui nécessite de définir comment deux agrégations sont combinées. Dans ton cas:

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

Btw, essayez d'écrire votre exemple avec reduce/reduceLeft - en raison de la relation de supertype entre le type d'élément et le type d'agrégation que ces deux méthodes ont, vous constaterez que cela conduit à un similaire erreur que celle que vous avez décrite.

64
axel22