我试图在这个https://www.youtube.com/watch?v=qwUYqv6lKtQ的帮助下理解 Scala 中的类型级编程。让我们考虑提供的代码:
trait Nat
class _0 extends Nat
class Succ[A <: Nat] extends Nat
type _1 = Succ[_0]
type _2 = Succ[_1] // = Succ[Succ[_0]]
type _3 = Succ[_2] // = Succ[Succ[Succ[_0]]]
type _4 = Succ[_3] // ... and so on
type _5 = Succ[_4]
sealed trait <[A <: Nat, B <: Nat]
object < {
def apply[A <: Nat, B <: Nat](implicit lt: <[A, B]): <[A, B] = lt
implicit def ltBasic[B <: Nat]: <[_0, Succ[B]] = new <[_0, Succ[B]] {}
implicit def inductive[A <: Nat, B <: Nat](implicit lt: <[A, B]): <[Succ[A], Succ[B]] = new <[Succ[A], Succ[B]] {}
}
sealed trait <=[A <: Nat, B <: Nat]
object <= {
def apply[A <: Nat, B <: Nat](implicit lte: <=[A, B]): <=[A, B] = lte
implicit def lteBasic[B <: Nat]: <=[_0, B] = new <=[_0, B] {}
implicit def inductive[A <: Nat, B <: Nat](implicit lt: <=[A, B]): <=[Succ[A], Succ[B]] = new <=[Succ[A], Succ[B]] {}
}
作者描述了定义的编译步骤val invalidComparison: _3 < _2 = <[_3, _2]:
- 该
apply方法需要一个隐式实例<[_2, _3] - 要找到该实例,编译器可以选择运行两个隐式方法中的任何一个 - 它会尝试调用该
inductive方法,但它需要一个隐式实例<[_1, _2] - 同样,编译器标记它可以调用该
inductive方法,但它需要一个类型的隐式实例<[_0, _1] ltBasic在这种情况下,编译器可以构建一个实例的信号的方法签名,<[_0, _1]因为_1 = Succ[0]- 现在,给定一个
<[_0, _1]编译器实例可以构建一个实例<[_1, _2] - 以同样的方式,给定一个
<[_1, _2]编译器实例可以构建一个<[_2, _3] - 给定 的实例
<[_2, _3],它可以安全地传递给apply方法并返回
问题是,编译器在哪里知道如何递减<[_2, _3],直到达到<[_0, _1]正确的隐式?
给定<[_0, _1]编译器的实例可以构建 的实例<[_1, _2],编译器怎么知道呢?