0

I'm trying to grasp the following article: Typelevel quicksort in Scala

At the very beginning the author introduces type-level natural numbers:

sealed trait Nat
final class _0 extends Nat
final class Succ[P <: Nat]() extends Nat
trait Sum[A <: Nat, B <: Nat] { type Out <: Nat }

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

  type Aux[A <: Nat, B <: Nat, C <: Nat] = Sum[A, B] { type Out = C }

  implicit def sum1[B <: Nat]: Aux[_0, B, B] = new Sum[_0, B] { type Out = B }
  implicit def sum2[A <: Nat, B <: Nat]
    (implicit sum : Sum[A, Succ[B]]): Aux[Succ[A], B, sum.Out] = new Sum[Succ[A], B] { type Out = sum.Out }
}

It works in the following manner:

scala> :t Sum[Succ[_0], Succ[Succ[_0]]]
Sum[Succ[_0],Succ[Succ[_0]]]{type Out = Succ[Succ[Succ[_0]]]}

Below is how I "understand" compiler works in this case. Firstly compiler finds apply method in companion object:

Sum.apply[Succ[_0], Succ[Succ[_0]]](implicit sum: Sum[Succ[_0], Succ[Succ[_0]]]): 
        Aux[Succ[_0], Succ[Succ[_0]], sum.Out] = sum 

And now it needs to find implicit parameter sum with the type Sum[Succ[_0], Succ[Succ[_0]]]. I understand that the right one is sum2 with A = _0 and B = Succ[Succ[_0]].

But how compiler does that? Does it perform some sort of pattern matching for output type to realize that if it takes _0 as A it will get the right output type? And finally is there any rules of how complex such pattern matching can be?

EDIT: The answer for the "Where does Scala look for implicits?" does a very good job explaining where and in what precedence compiler is looking for implicit definitions. My question is rather about type inference mechanism. How does compiler represent such recursive types as Sum in the example? And how does it match the output type of implicit definition when some part of it is unknown?

Community
  • 1
  • 1
dkolmakov
  • 628
  • 5
  • 11

0 Answers0