如何正确定义 f-bound 多态类型的存在性
How to properly define existential for a f-bound polymorphic type
这里有几个类似的问题,我阅读了它们,但没有找到可以让我的代码正常工作的答案。我想我遇到了一个极端情况,需要比正常情况更精确的类型规范。
我的情况用两个词来形容。我想构建非常简单的异构列表示例来加深我对 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-bounded 多态性可以以自然的方式帮助我。我得到以下代码:
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 绑定变体?
您只需重写 HCons
,将 T <: HList[T]
替换为 T <: HAny
:
final case class HCons[H, T <: HAny](head : H, tail : T) extends HList[HCons[H,T]] { ... }
这里有几个类似的问题,我阅读了它们,但没有找到可以让我的代码正常工作的答案。我想我遇到了一个极端情况,需要比正常情况更精确的类型规范。
我的情况用两个词来形容。我想构建非常简单的异构列表示例来加深我对 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-bounded 多态性可以以自然的方式帮助我。我得到以下代码:
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 绑定变体?
您只需重写 HCons
,将 T <: HList[T]
替换为 T <: HAny
:
final case class HCons[H, T <: HAny](head : H, tail : T) extends HList[HCons[H,T]] { ... }