2012-11-02 11 views
8

Próbuję utworzyć listę niektórych cech, sparametryzowane przez typ za pomocą CRTP, i nie można dowiedzieć się, jak wyrazić ograniczenia typu. Oto przykładowy kod, który ilustruje problem:Jak wyrazić ograniczenia typu dla typów wyższych typu

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)) 
} 

Więc próbuję utworzyć listę obiektów, które są zgodne z cechą B. Jednak ten kod nie będzie kompilować i daje następujący błąd:

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]()

Dla mnie wydaje się _ <: Z forSome { type Z <: A[Z] } rzeczywiście jest co najmniej tak rygorystyczne jak Y <: A[Y] ale może nie jestem czegoś brakuje.

Pytanie więc brzmi: jakie ograniczenia powinny obowiązywać dla funkcji emptyList, aby poprawnie obsługiwać B?

+1

myślę tutaj problem polega na tym, co naprawdę chcesz to znaczy 'X [_ <: Z forall {typ Z <: A [Z]}]' - tj chcesz typ wyższej rangi. Nie wiem, jak to osiągnąć! – Submonoid

Odpowiedz

4

Po pewnym okresie prób i błędów, udało mi się go uruchomić. Uwaga: kompilator mówi nam, że parametry typu w A [+ X] i B [+ Y] muszą być kowariancyjne.

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

Próbowałem także ustawień kowariancji, ale nie udało mi się uzyskać poprawnej metody emptyList. Dzięki, że to wymyśliłeś. – fhusb

Powiązane problemy