2012-11-02 9 views
8

Sto cercando di creare un elenco di alcuni tratti, parametrizzati da un tipo utilizzando il CRTP e non riesco a capire come esprimere i vincoli di tipo. Ecco alcuni esempi di codice che illustra il problema:Come esprimere i vincoli di tipo per il tipo più elevato

trait A[X] { 
    def x: X 
} 

trait B[Y <: A[Y]] { 
    def y(i: Int): Y 
} 

case class C(i: Int) extends A[C] { 
    def x = C(i) 
} 

case class D(i: Int) extends A[D] { 
    def x = D(i) 
} 

case class E() extends B[C] { 
    def y(i: Int) = C(i) 
} 

case class F() extends B[D] { 
    def y(i: Int) = D(i) 
} 

object Program extends App { 
    def emptyList[X[_ <: Z forSome { type Z <: A[Z] } ]]() = collection.mutable.ListBuffer.empty[X[_]] 

    val myList = emptyList[B]() 
    myList += E() 
    myList += F() 

    println(myList.map(_.y(2).x)) 
} 

Così qui sto cercando di creare un elenco di oggetti conformi alla caratteristica B. Tuttavia questo codice non viene compilato, e dà il seguente errore:

kinds of the type arguments (B) do not conform to the expected kinds of the type parameters (type X). B's type parameters do not match type X's expected parameters: type Y's bounds >: Nothing <: A[Y] are stricter than type _'s declared bounds >: Nothing <: Z forSome { type Z <: A[Z] } val myList = emptyList[B]()

A me sembra che _ <: Z forSome { type Z <: A[Z] } è infatti almeno altrettanto rigorose Y <: A[Y] ma forse mi manca qualcosa.

Quindi la domanda è: quali devono essere i vincoli sulla funzione emptyList per gestire correttamente B?

+1

Credo che il problema qui è che cosa si vuole veramente è quello di dire 'X [_ <: Z FORALL {type Z <: A [Z]}]' - vale a dire che si desidera un tipo più alto rango. Non ho ancora capito come riuscirci! – Submonoid

risposta

4

Dopo alcune prove ed errori, ho avuto modo di funzionare. Nota: il compilatore ci dice che i parametri di tipo in A [+ X] e B [+ Y] devono essere covarianti.

trait A[+X] { 
    def x: X 
} 

trait B[+Y <: A[Y]] { 
    def y(i: Int): Y 
} 

case class C(i: Int) extends A[C] { 
    def x = C(i) 
} 

case class D(i: Int) extends A[D] { 
    def x = D(i) 
} 

case class E() extends B[C] { 
    def y(i: Int) = C(i) 
} 

case class F() extends B[D] { 
    def y(i: Int) = D(i) 
} 


object Test extends App { 
    def emptyList[X[Y <: A[Y]]] = collection.mutable.ListBuffer.empty[X[Y forSome {type Y <: A[Y]} ]] 

    val myList = emptyList[B] 
    myList += E() 
    myList += F() 

    println(myList.map(_.y(2).x)) 
} 
+0

Stavo provando anche le impostazioni di covarianza, ma non sono riuscito a ottenere il metodo emptyList corretto. Grazie per averlo capito. – fhusb

Problemi correlati