4

這裏有幾個類似的問題,我讀了它們,發現沒有答案可以讓我的代碼工作。我想我碰到了一個需要比正常情況下更精確的類型規格的角落案例。如何正確定義一個f綁定多態類型的存在

我的情況用兩個字。我想創建非常簡單的異構列表示例來加深我對scala語言的理解。我給自己設置的限制是:沒有任何形式的暗示,只是普通的scala類型系統。 Implicits可以使許多事情變得更容易,但我想努力嘗試。

我已經工作的代碼,但我想改進它。在這裏它是:

sealed trait HList { 
    type Self <: HList 
    def self : Self 

    def prepend[H](head : H) = HCons[H, Self](head, self) 
    def ::[H](head : H) = prepend(head) 

    type Merge[X <: HList] <: HList 
    def merge[X <: HList](other : X) : Merge[X] 

    def :::[X <: HList](other : X) = other.merge[Self](self) 
} 

sealed trait HNil extends HList { 
    override type Self = HNil 
    override def self = this 

    override type Merge[X <: HList] = X 
    override def merge[X <: HList](other : X) : Merge[X] = other 
} 
case object HNil extends HNil 

final case class HCons[H, T <: HList](head : H, tail : T) extends HList { 
    override type Self = HCons[H,T] 
    override def self = this 

    override type Merge[X <: HList] = HCons[H, T#Merge[X]] 
    override def merge[X <: HList](other : X) : Merge[X] = HCons(head, tail.merge(other)) 
} 

Merge類型構造表示追加兩個列表的類型的結果。需要跟蹤所有嵌套類型。這裏是結果:

val x = "str" :: true :: HNil 
val s : String = x.head 
val b : Boolean = x.tail.head 

val y = 0.5 :: 12 :: HNil 
val d : Double = y.head 
val i : Int = y.tail.head 

val l = x ::: y 
val r = y.merge(x) 

val sl : String = l.head 
val sb : Boolean = l.tail.head 
val sd : Double = l.tail.tail.head 
val si : Int = l.tail.tail.tail.head 

val rd : Double = r.head 
val ri : Int = r.tail.head 
val rl : String = r.tail.tail.head 
val rb : Boolean = r.tail.tail.tail.head 

現在我已經做了無聊的介紹。我擔心這一點我已經失去了一半的讀者。我希望我可以將代碼摺疊爲單行。

所以真正的問題是Self類型和self方法。他們看起來很醜,我想擺脫他們。我相信f-bound多態可以以自然的方式幫助我。我得到了下面的代碼:

type HAny = X forSome {type X <: HList[X]} 
sealed trait HList[Self <: HList[Self]] {this : Self => 
    def prepend[H](head : H) = HCons[H, Self](head, this) 
    def ::[H](head : H) = prepend(head) 

    type Merge[X <: HList[X]] <: HAny 
    def merge[X <: HList[X]](other : X) : Merge[X] 

    def :::[X <: HList[X]](other : X) = other.merge[Self](this) 
} 

sealed trait HNil extends HList[HNil] { 
    override type Merge[X <: HList[X]] = X 
    override def merge[X <: HList[X]](other : X) : Merge[X] = other 
} 
case object HNil extends HNil 
final case class HCons[H, T <: HList[T]](head : H, tail : T) extends HList[HCons[H,T]] { 
    override type Merge[X <: HList[X]] = HCons[H, T#Merge[X]] 
    override def merge[X <: HList[X]](other : X) : Merge[X] = HCons[H, T#Merge[X]](head, tail.merge(other)) 
} 

Scala編譯器產生的錯誤,給我很少的見解:

[error] App.scala:23: type arguments [H,T#Merge[X]] do not conform to method apply's type parameter bounds [H,T <: SelApp1.this.HList[T]] 
[error]  override def merge[X <: HList[X]](other : X) : Merge[X] = HCons[H, T#Merge[X]](head, tail.merge(other)) 
[error]                 ^
[error] one error found 

轉化爲F-約束多態性順利的前置部分。合併部分產生錯誤。我需要對Merge類型進行抽象,所以我用HAny存在類型對它進行了限定,就像我在前面的示例中使用HList而沒有任何其他類型規範。

但是在後一種情況下,由於編譯器抱怨不恰當的類型,一些類型信息丟失。那麼我如何定義存在類型來存儲構建HCons所需的所有類型信息呢?也許我需要更復雜的調整來將抽象類型解決方案轉換爲f-bound變體?

回答

3

你只是重寫HCons,更換T <: HList[T]T <: HAny

final case class HCons[H, T <: HAny](head : H, tail : T) extends HList[HCons[H,T]] { ... } 
+0

費德里科,這是它的工作原理方面有很大的答案,但請你提供有關爲什麼原來的代碼沒有按一些細節不工作,這是嗎?關鍵區別在哪裏?我不認爲我理解這個訣竅的方式是我可以在必要時再次複製它。 – SergGr