2013-04-19 14 views
32

Sto cercando di capire come piega e piega e il rispettivo riduce e riduce il lavoro sinistro. Ho usato piega e foldLeft come il mio esempioScala: piega contro piegaLeft

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) 

Perché fold non ha funzionato come foldLeft? Che cos'è Serializable with Equals? Capisco fold e foldLeft ha una firma API leggermente diversa in termini di parametri generici. Si prega di avvisare. Grazie.

+3

Possibile duplicato di [Differenza tra piega e piega sinistra o piega destra?] (Http://stackoverflow.com/q/6253978) –

+0

Quale versione di scala? –

+0

La mia versione di scala è 2.10.1 – thlim

risposta

54

Il metodo fold (originariamente aggiunto per il calcolo parallelo) è meno potente di foldLeft in termini di tipi a cui può essere applicato. La sua firma è:

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

Ciò significa che il tipo su cui viene eseguita la piegatura deve essere un supertipo del tipo di elemento di raccolta.

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

La ragione è che fold può essere implementato in parallelo, mentre foldLeft non può. Questo non è solo a causa della parte *Left che implica che foldLeft passa da sinistra a destra in sequenza, ma anche perché l'operatore op non può combinare i risultati calcolati in parallelo - definisce solo come combinare il tipo di aggregazione B con il tipo di elemento A, ma non come combinare due aggregazioni di tipo B. Il metodo fold, a sua volta, definisce questo, perché il tipo di aggregazione A1 deve essere un supertipo del tipo di elemento A, ovvero A1 >: A. Questa relazione supertipo consente allo stesso tempo di piegare l'aggregazione e gli elementi e di combinare le aggregazioni, sia con un singolo operatore.

Tuttavia, questa relazione di supertipo tra l'aggregazione e il tipo di elemento indica anche che il tipo di aggregazione A1 nell'esempio dovrebbe essere il supertipo di (ArrayBuffer[Int], Int). Poiché l'elemento zero della tua aggregazione è ArrayBuffer(1, 2, 4, 5) del tipo ArrayBuffer[Int], il tipo di aggregazione viene considerato come il supertipo di entrambi, e questo è Serializable with Equals, l'unico limite superiore di una tupla e un buffer di matrice.

In generale, se si desidera consentire la piegatura parallela per tipi arbitrari (operazione eseguita fuori servizio), è necessario utilizzare il metodo aggregate che richiede la definizione di come vengono combinate due aggregazioni. Nel tuo caso:

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

Btw, provare a scrivere il vostro esempio con reduce/reduceLeft - a causa del rapporto supertipo tra il tipo di elemento e il tipo di aggregazione che entrambi questi metodi hanno, troverete che porta a un errore simile a quello che hai descritto.