如何正确定义f-bound多态类型的存在性

时间:2017-02-04 02:56:34

标签: scala existential-type type-level-computation f-bounded-polymorphism

这里有几个类似的问题,我读了它们,发现没有可以让我的代码工作的答案。我想我遇到了需要比平时更精确的类型规范的角落案例。

我的情况用两个字。我想构建一个非常简单的异构列表示例,以加深我对scala语言的理解。我对自己设置了限制:没有任何形式的隐含,只是普通的scala类型系统。隐含可以使许多事情变得更容易,但我想努力。

我已经使用了代码,但我想改进它。这是:

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-bound多态性。合并部分产生错误。我需要对Merge类型进行抽象,因此我将其与HAny存在类型绑定在一起,就像在早期的示例中我使用HList而没有任何其他类型规范。

但是在后一种情况下,由于编译器抱怨不合适的类型,因此某些类型信息会丢失。那么如何定义存在类型来保存构建HCons所需的所有类型信息?也许我需要更复杂的调整来将抽象类型解决方案转移到f-bound变体?

1 个答案:

答案 0 :(得分:3)

您必须重写HCons,将T <: HList[T]替换为T <: HAny

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