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

后端 未结 1 1538
佛祖请我去吃肉
佛祖请我去吃肉 2021-01-16 07:08

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

We are exposed to a Sum type whose apply looks like this:

def apply         


        
相关标签:
1条回答
  • 2021-01-16 08:09

    Types Sum[A, B] and Sum.Aux[A, B, C] = Sum[A, B] { type Out = C } are different. The latter is a subtype of the former. Also Sum[A, B] is existential type 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?

    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

    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. And every defined implicit "knows" its specific C. But if you return just Sum[A, B] this C will be forgotten.

    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].

    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.

    Sure. x.Out is no longer _1, it's just some abstract x.Out, and implicit can't be resolved.

    0 讨论(0)
提交回复
热议问题