2012-11-02 41 views
8

我想創建一些特徵的列表,通過使用CRTP的類型進行參數化,並且無法弄清楚如何表達類型約束。這裏是一個能說明問題的一些示例代碼:如何表達類型約束更高kinded類型

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

所以在這裏我想創建符合到B特質對象的列表。然而,這代碼不能編譯,並提供了以下錯誤:

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

對我來說,這似乎是_ <: Z forSome { type Z <: A[Z] }確實是至少同樣嚴格Y <: A[Y]但也許我失去了一些東西。

所以問題是 - 什麼約束應該在emptyList函數來正確處理B?

+1

我認爲這裏的問題是,你真正想要的是說'X [_ <:Z forAll {type Z <:A [Z]}]' - 即你想要一個更高等級的類型。不過,我還沒有制定出如何實現這個目標。 – Submonoid

回答

4

經過一些試驗和錯誤,我得到它的工作。注意:編譯器告訴我們A [+ X]和B [+ Y]中的類型參數必須是協變的。

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

我也在嘗試使用協方差設置,但沒有設法使emptyList方法正確。感謝您找出答案。 – fhusb