整数和Peano自然之间的双向转换

时间:2015-02-10 09:46:16

标签: scala types dependent-type path-dependent-type

我在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

我试图通过利用依赖方法返回类型来反转这种对应关系,如果可能的话。因此,首先需要的是IntNat

的容器
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]

知道为什么吗?

1 个答案:

答案 0 :(得分:2)

因为int2pair返回类型只是Pair,而不是Pair { type N = _2 }if / else在运行时发生,编译器无法知道将采用哪个分支。

AFAIK从值到类型的唯一方法是使用宏。您可能需要查看shapeless' singleton support