为什么我们需要为某些类型计算的输出指定精炼类型(或其等效的Aux)?

时间:2018-02-05 17:10:36

标签: scala dependent-type type-level-computation path-dependent-type

https://jto.github.io/articles/typelevel_quicksort中:

我们接触到Sum类似apply的{​​{1}}类型:

def apply[A <: Nat, B <: Nat](implicit sum: Sum[A, B]): Aux[A, B, sum.Out] = sum

现在,我们可以直接使用类型细化而不是Aux,但问题仍然存在:为什么这(显式返回类型)是必要的? apply的返回类型的Sum#Out类型是否等于sum.Out是不是“显而易见”?

如果我们删除它并且我们只使用val x = Sum[_0, _1],它看起来很好,除了添加val y = Sum[x.Out, _1]不起作用,说编译器找不到隐式Sum。

为什么编译器似乎“忘记”了x.Out的确切类型?

1 个答案:

答案 0 :(得分:3)

类型Sum[A, B]Sum.Aux[A, B, C] = Sum[A, B] { type Out = C }不同。后者是前者的亚型。 Sum[A, B]也是存在类型Sum.Aux[A, B, _]

  

apply的返回类型不会“显而易见”   Sum#Out类型等于sum.Out?

没有

def apply[A <: Nat, B <: Nat](implicit sum: Sum[A, B]) = sum

相同
def apply[A <: Nat, B <: Nat](implicit sum: Sum[A, B]): Sum[A, B] = sum

首先,您要定义隐含:使用sum1sum2进行归纳或简单地

implicit val sum00: Aux[_0, _0, _0] = new Sum[_0, _0] { type Out = _0 }
implicit val sum01: Aux[_0, _1, _1] = new Sum[_0, _1] { type Out = _1 }
implicit val sum10: Aux[_1, _0, _1] = new Sum[_1, _0] { type Out = _1 }
implicit val sum11: Aux[_1, _1, _2] = new Sum[_1, _1] { type Out = _2 }
...

然后当你写

def apply[A <: Nat, B <: Nat](implicit sum: Sum[A, B]): Aux[A, B, sum.Out] = sum

只知道AB就足以解决隐含问题。每个定义的隐含“知道”其特定的C。但如果您只返回Sum[A, B],则C会被遗忘。

您可以定义

def apply[A <: Nat, B <: Nat, C <: Nat](implicit sum: Aux[A, B, C]): Aux[A, B, C] = sum

但是您必须手动指定CSum[_2, _3, _5]

  

如果我们删除它并且我们只使用val x = Sum[_0, _1],它看起来很好,   除了添加val y = Sum[x.Out, _1]将不起作用,说   编译器找不到隐式Sum。

不确定。 x.Out不再是_1,它只是一些抽象的x.Out,隐式无法解析。