我在Scala中使用自然数字的标准类型编码。出于此问题的目的,以下定义将执行:
sealed trait Nat
sealed trait _0 extends Nat
sealed trait Succ[N <: Nat] extends Nat
我可以使用编译器将这些Nat
类型转换为实际数字,例如通过定义
class NatConverter[N <: Nat](val n: Int)
implicit val zeroConv: NatConv[_0] = new NatConv(0)
implicit def succConv[N <: Nat](implicit ev: NatConv[N]): NatConv[Succ[N]] =
new NatConv(ev.n + 1)
def nat2value[N <: Nat](implicit ev: NatConv[N]) = ev.n
这有效:
type _1 = Succ[_0]
type _2 = Succ[_1]
nat2value[_2] // gives 2
我试图通过利用依赖方法返回类型来反转这种对应关系,如果可能的话。因此,首先需要的是Int
和Nat
trait Pair {
type N <: Nat
def n: Int
}
现在,我希望能够隐式地将Int
转换为Pair
的实例,并使用N
的正确值。这是
implicit def int2pair(a: Int): Pair =
if (a == 0) new Pair {
type N = _0
val n = 0
}
else {
val previous = int2pair(a - 1)
new Pair {
type N = Succ[previous.N]
val n = a
}
}
这确实可以编译。不幸的是
val two = int2pair(2)
implicitly[two.N =:= _2]
失败,以及
val two = int2pair(2)
implicitly[two.N <:< _2]
知道为什么吗?
答案 0 :(得分:2)
因为int2pair
的返回类型只是Pair
,而不是Pair { type N = _2 }
。 if
/ else
在运行时发生,编译器无法知道将采用哪个分支。
AFAIK从值到类型的唯一方法是使用宏。您可能需要查看shapeless' singleton support。