gpt4 book ai didi

scala - 在 scala 中,如何使类型类适用于 Aux 模式? - 第2部分

转载 作者:行者123 更新时间:2023-12-04 03:42:03 25 4
gpt4 key购买 nike

这是后续问题: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 , 其中, T1ForH 的最简单和具体的定义,不幸的是它不起作用。 @Dan Simon(在 T2 中)提出了一项改进,它使用类型参数让 spark 编译器发现 ForH <:< Base.Aux[HNil]

现在假设我想扩展@Dan Simon 的解决方案,这样类型类适用于所有类,如 ForH对于不同种类的 HList(HNil 的 super 特性)。 T3 中有 2 个自然扩展& T4分别。

不幸的是,它们都不起作用。 T4可以用以下事实来解释 ForH <:< Aux[HList]无效,但是 T3不能用这个借口。另外也没有办法改进编译成功。

为什么类型类召唤算法在这种情况下失败了?应该怎么做才能使类型类模式真正起作用?

最佳答案

再次,T1.summon(v)不编译因为 T1.t1不是候选人,手动解决T1.summon(v)(T1.t1)不编译。

对于 T3T4 T3.t1[HNil, Base.ForH] , T4.t1[HNil, Base.ForH]将是候选人

T3.summon(v)(T3.t1[HNil, Base.ForH]) // compiles
T4.summon(v)(T4.t1[HNil, Base.ForH]) // compiles

但问题是H首先被推断,它被推断为Nothing但是t1[Nothing, Base.ForH]不满足类型界限。

所以问题不在于隐式解析算法,没关系,问题在于类型推断(我们都知道它在 Scala 中非常弱)。

你可以阻止H被推断得太快了 Nothing如果你修改 T3.t1 , T4.t1

object T3 extends TypeClasses {    
implicit def t1[
H <: HList,
T <: Base/*.Lt[H]*/
](implicit ev: 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]*/
](implicit ev: T <:< Base.Aux[H]): TypeClass[T] = new TypeClass[T] {
type HH = H
}
}

T3.summon(v) // compiles
T4.summon(v) // compiles

关于scala - 在 scala 中,如何使类型类适用于 Aux 模式? - 第2部分,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65853961/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com