【发布时间】:2021-01-22 23:07:57
【问题描述】:
这是一个后续问题:In scala, how to make type class working for Aux pattern?
考虑以下示例:
trait Base {
type Out
def v: Out
}
object Base {
type Aux[T] = Base { type Out = T }
type Lt[T] = Base { type Out <: T }
class ForH() extends Base {
final type Out = HNil
override def v: Out = HNil
}
object ForH extends ForH
}
trait TypeClasses {
class TypeClass[B]
def summon[B](b: B)(implicit ev: TypeClass[B]): TypeClass[B] = ev
}
object T1 extends TypeClasses {
implicit def t1: TypeClass[Base.Aux[HNil]] = new TypeClass[Base.Aux[HNil]]
implicit def t2: TypeClass[Int] = new TypeClass[Int]
}
object T2 extends TypeClasses {
implicit def t1[T <: Base.Aux[HNil]]: TypeClass[T] = new TypeClass[T]
}
object T3 extends TypeClasses {
implicit def t1[
H <: HList,
T <: Base.Lt[H]
]: TypeClass[T] = new TypeClass[T] {
type HH = H
}
}
object T4 extends TypeClasses {
implicit def t1[
H <: HList,
T <: Base.Aux[H]
]: TypeClass[T] = new TypeClass[T] {
type HH = H
}
}
it("No Aux") {
val v = 2
T1.summon(v) // works
}
it("Aux1") {
val v = new Base.ForH()
T1.summon(v) // oops
T1.summon(Base.ForH) // oops
val v2 = new Base.ForH(): Base.Aux[HNil]
T1.summon(v2) // works!
}
it("Aux2") {
val v = new Base.ForH()
T2.summon(v) // works
T2.summon(Base.ForH) // works
val v2 = new Base.ForH(): Base.Aux[HNil]
T2.summon(v2) // works
}
it("Aux3") {
val v = new Base.ForH()
T3.summon(v) // oops
T3.summon(Base.ForH) // oops
val v2 = new Base.ForH(): Base.Aux[HNil]
T3.summon(v2) // oops
}
it("Aux4") {
val v = new Base.ForH()
T4.summon(v) // oops
T4.summon(Base.ForH) // oops
val v2 = new Base.ForH(): Base.Aux[HNil]
T4.summon(v2) // oops
}
TypeClasses 的所有实现都包含其底层TypeClass 的隐式范围,其中T1 是ForH 的最简单和具体的定义,不幸的是它不起作用。 @Dan Simon 提出了一项改进(在 T2 中),它使用类型参数允许 spark 编译器发现 ForH <:< Base.Aux[HNil]
现在想象一下,我想扩展@Dan Simon 的解决方案,以便类型类适用于所有类,如ForH 用于不同类型的 HList(HNil 的超特征)。 2个自然扩展分别在T3和T4。
不幸的是,它们都不起作用。 T4 可以解释为ForH <:< Aux[HList] 无效,但T3 不能以此为借口。另外,也没有办法改进编译成功。
为什么类型类召唤算法失败了?应该怎么做才能使类型类模式真正起作用?
【问题讨论】:
-
仅供参考,
T3和T4在 Scala 3 (3.0.0-M3) 中似乎都可以正常工作。所以也许这真的只是 Scala 2 的一个错误/限制。 -
哇...我认为 T3 不应该工作。那里发生了什么:-|
-
如果
H没有用在隐式参数或隐式返回类型中,那么编译器就没有什么可以继续推断H了。 -
@Jasper-M(叹息)你可能是对的,我浏览了整个shapeless的源代码,到目前为止只在隐式参数中找到了Aux
-
@DanSimon,我会尝试详细说明:ForH <: aux dotty>
标签: scala typeclass abstract-data-type type-alias scala-2.13