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

相关问题