2013-05-24 8 views
7

devo this function convertire un Array ad un ParArray, dando il numero di thread come parametro:parametri di tipo generico per la conversione in parallelo la raccolta

def parN[T](collection: Array[T], n: Int) = { 
    val parCollection = collection.par 
    parCollection.tasksupport = new ForkJoinTaskSupport(
     new concurrent.forkjoin.ForkJoinPool(n)) 
    parCollection 
} 

Ora mi piacerebbe fare questo generico, tale da funziona con collezioni diverse da Array:

def parN[S, T[S] <: Parallelizable[S, ParIterable[S]]](collection: T[S], n: Int) = { 
    val parCollection = collection.par 
    parCollection.tasksupport = new ForkJoinTaskSupport(
     new concurrent.forkjoin.ForkJoinPool(n)) 
    parCollection 
} 

Ma when I call it con parN(Array(1, 2, 3), 2), ottengo questo errore:

inferred type arguments [Int,Array] do not 
conform to method parN's type parameter bounds 
[S,T[S] <: scala.collection.Parallelizable[S,scala.collection.parallel.ParIterable[S]]] 

D'altra parte, questo sta lavorando:

val x: Parallelizable[Int, ParIterable[Int]] = Array(1, 2, 3) 

Tutte le idee che cosa potrebbe essere sbagliato con i miei parametri di tipo?

risposta

5

Prima di tutto, si noti che questo è un problema specifico Array: il metodo funziona per List o qualsiasi altra raccolta normale (ad eccezione di quelli con più parametri di tipo, o nessuno). Esempio:

scala> parN(List(1,2,3), 2) 
res17: scala.collection.parallel.ParIterable[Int] = ParVector(1, 2, 3) 

scala> parN(Set(1,2,3), 2) 
res18: scala.collection.parallel.ParIterable[Int] = ParSet(1, 2, 3) 

Array è sempre un caso particolare quando si tratta di collezioni, perché ... non è una collezione. A causa di Java, la sua definizione è final class Array[T] extends Serializable with Cloneable. Tuttavia, esistono due impliciti, disponibili ovunque, che possono convertire Array in un tipo di raccolta (ArrayOps e WrappedArray). E questi tipi fanno implementare Parallelizable, quindi tutto dovrebbe andare bene ... tranne inferenza di tipo si mette di mezzo:

tuo parametro di tipo è definito solo come T[S], in modo che quando si riceve una Array[Int], che sarà lieto di dedurre Array[Int], e poi controllare i limiti: fallimento, Array non si estende Parallelizable. Gioco finito.

vedo due opzioni:

  • Si può esplicitamente dire che si desidera un Parallelizable:

    def parN[S](collection: Parallelizable[S, ParIterable[S]], n: Int) 
    

    Oppure, se avete bisogno di accedere al tipo effettivo T (nel tuo caso no, ma chi lo sa):

    def parN[S, T[S] <: Parallelizable[S, ParIterable[S]]](collection: T[S] with 
        Parallelizable[S, ParIterable[S]], n: Int) 
    
  • oppure si può accettare anythin g che può essere convertito in modo implicito un Parallelizable, utilizzando un parametro implicito:

    def parN[S, T <% Parallelizable[S, ParIterable[S]]](collection: T, n: Int) 
    

    che è la versione breve di:

    def parN[S, T](collection: T, n: Int)(implicit ev: T => 
        Parallelizable[S, ParIterable[S]]) 
    

Tutti coloro dovrebbe funzionare. Nel tuo caso ti consiglierei il primo: è il più leggibile che fa il lavoro.

+0

WOw, bastonatemi. Il modello di classe del tipo è il modo per andare qui. Tuttavia, non è necessario aggiungere un requisito ': Manifest' per lavorare con gli array? – wheaties

+1

@wheaties no 'Manifest \ ClassTag' non è nemmeno necessario perché il suo metodo non sta effettivamente creando una matrice (' Parallelizable.par' non ha bisogno di un manifest, sa sempre come creare una raccolta par). E nel caso degli array, avvolge solo l'array originale, non lo copia nemmeno. – gourlaysama

+0

Grazie per la risposta dettagliata, ho finito per utilizzare una vista "<%" associata a 'CustomParallelizable'. – ValarDohaeris

Problemi correlati