2015-04-24 4 views
5

Dopo aver esaminato alcuni esempi di tipi con maggiore scalabilità Scala nel tutorial this, ho iniziato a giocare con (a) impliciti e (b) tecniche per scrivere metodi che gestiscono genericamente sottoclassi di un tratto che è definito come un livello superiore. tipo gentilitato. Ho già avuto una grande risposta in (b) here che mi si sta avvicinando alla soluzione del problema di seguito:L'ambiguità implicita di Scala non viene risolta senza fastidioso argomento fittizio per contrassegnare il tipo.

voglio creare una fabbrica per la creazione di contenitori Singleton (Set, liste, array) che avvolgono l'elemento che Passo alla funzione di fabbrica. [Anche se esiste già una libreria Scala , lo faccio come un esercizio di apprendimento. Ma, hey ... se ce n'è uno, per favore fatemelo sapere]

Il risultato finale dovrebbe mi permetta di fare questo:!

scala> var j: Set[String] = wrapItemInContainer("foo") 
j: Set[String] = Set(foo) 

scala> var k: List[Int] = wrapItemInContainer(9) 
k: List[Int] = List(9) 

La soluzione mi è venuto in mente è illustrato di seguito. Devo fornire un fastidioso argomento finale fittizio in modo che possa aiutare il compilatore a capire che tipo di contenitore voglio. Funziona, ma sono sconcertato dal fatto che la firma del tipo della variabile che voglio assegnare il risultato a (j, k..etc.) Non dia al compilatore informazioni sufficienti per capire quale ContainerFactory è implicitamente definito deve essere usato

Questa soluzione goffa funziona:

trait ContainerFactory[M[_]] { def put[A](x: A): M[A] } 


implicit val factory = new ContainerFactory[List] { def put[A](x: A) = List(x) } // factory for List containers 
implicit val factory2 = new ContainerFactory[Set] { def put[A](x: A) = Set(x)} // factory for Set containers 

def wrapItemInContainer[ M[A]: ContainerFactory, A](item: A, helper: M[A]) : M[A] = { 
    val c = implicitly[ContainerFactory[M]]        
    c.put(item) 
} 

var j: List[Int] = wrapItemInContainer(9, List(0)) 

Ma voglio davvero qualcosa con il secondo argomento rumorosa:

def wrapItemInContainer[ M[A]: ContainerFactory, A](item: A) : M[A] = { 
    val c = implicitly[ContainerFactory[M[A]]]        
    c.put(item) 
} 

var j: List[Int] = wrapItemInContainer(9) // this does not work. 

ottengo questo errore:

<console>:17: error: ambiguous implicit values: 
both value factory of type => ContainerFactory[List] 
and value factory2 of type => ContainerFactory[Set] 
match expected type ContainerFactory[M] 
     var j: List[Int] = wrapItemInContainer(9) 

Tutte le idee o i consigli sono molto apprezzati!

-Chris

+2

Per farti sapere: questo è ciò che a volte viene chiamato "Puntato". Di solito fa parte della classe di tipo Applicativo, ad es. In [scalaz] (https://github.com/scalaz/scalaz/blob/466d4da2951666f736d554104a2b3b956e4e6885/core/src/main/scala/scalaz/Applicative.scala). – phg

risposta

6

Hai bisogno di fare il covariante fabbrica in M. Vedere https://groups.google.com/forum/#!topic/scala-language/dQEomVCH3CI e https://issues.scala-lang.org/browse/SI-7332.

Questo compila:

import language.higherKinds 

trait Factory[+M[_], A] { def put(x: A): M[A] } 

implicit def factory1[A] = 
    new Factory[List, A] { def put(x: A) = List(x) } 
implicit def factory2[A] = 
    new Factory[Set, A] { def put(x: A) = Set(x) } 

def wrap[M[_], A](a: A)(
    implicit factory: Factory[M, A]): M[A] = 
    factory.put(a) 

val j: Set[String] = wrap("foo") 
val k: List[Int] = wrap(9) 

mi sono preso la libertà di abbreviare i vostri nomi. Ho anche seguito il consiglio che hai ricevuto a how to generically handle Scala Higher-kinded types when coding factories for generating containers of items of type 'X' per rendere A un parametro di tipo sulla fabbrica stessa.

Problemi correlati