简体   繁体   English

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

[英]Why do we need to specify a refined type (or its equivalent Aux) for the output of certain type computations?

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

We are exposed to a Sum type whose apply looks like this: 我们接触到一个Sum类型,其apply如下所示:

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

Now, we could use type refinement directly instead of Aux, but the question remains: why is this (the explicit return type) necessary? 现在,我们可以直接使用类型细化而不是Aux,但问题仍然存在:为什么这(显式返回类型)是必要的? Wouldn't it be "obvious" that the return type of apply would have a Sum#Out type equal to sum.Out? apply的返回类型是否具有等于sum的Sum#Out类型,这是不是“显而易见”.Out?

If we remove it and we just use val x = Sum[_0, _1] , it looks fine, except adding val y = Sum[x.Out, _1] will not work, saying the compiler couldn't find the implicit Sum. 如果我们删除它并且我们只使用val x = Sum[_0, _1] ,它看起来很好,除了添加val y = Sum[x.Out, _1]将不起作用,说编译器找不到隐式Sum。

How come the compiler seems to "forget" the exact type of x.Out? 为什么编译器似乎“忘记”了x.Out的确切类型?

Types Sum[A, B] and Sum.Aux[A, B, C] = Sum[A, B] { type Out = C } are different. 类型Sum[A, B]Sum.Aux[A, B, C] = Sum[A, B] { type Out = C }是不同的。 The latter is a subtype of the former. 后者是前者的亚型。 Also Sum[A, B] is existential type Sum.Aux[A, B, _] . Sum[A, B]也是存在类型Sum.Aux[A, B, _]

Wouldn't it be "obvious" that the return type of apply would have a Sum#Out type equal to sum.Out? apply的返回类型是否具有等于sum的Sum#Out类型,这是不是“显而易见”.Out?

No, 没有,

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

is the same as 是相同的

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

The thing is that firstly you define implicits: either inductively with sum1 , sum2 or simply 首先,你要定义sum2 :要么是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 }
...

Then when you write 然后当你写

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

knowing just A and B is enough for resolving implicit. 只知道AB足以解决隐式问题。 And every defined implicit "knows" its specific C . 每个定义的隐含“知道”其特定的C But if you return just Sum[A, B] this C will be forgotten. 但如果你只返回Sum[A, B]这个C就会被遗忘。

You could define 你可以定义

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

but then you will have to call it specifying C manually: Sum[_2, _3, _5] . 但是你必须手动指定CSum[_2, _3, _5]

If we remove it and we just use val x = Sum[_0, _1] , it looks fine, except adding val y = Sum[x.Out, _1] will not work, saying the compiler couldn't find the implicit Sum. 如果我们删除它并且我们只使用val x = Sum[_0, _1] ,它看起来很好,除了添加val y = Sum[x.Out, _1]将不起作用,说编译器找不到隐式Sum。

Sure. 当然。 x.Out is no longer _1 , it's just some abstract x.Out , and implicit can't be resolved. x.Out不再是_1 ,它只是一些抽象的x.Out ,并且隐含无法解析。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM