我正在尝试打印peano数字,如下所示:
sealed trait Nat
trait _0 extends Nat
trait Succ[N <: Nat] extends Nat
type _1 = Succ[_0]
type _2 = Succ[_1]
class RepNat[T <: Nat](val value: Int)
def rep[T <: Nat](implicit r: RepNat[T]) = r.value
implicit val repZero = new RepNat[_0](0)
implicit def repSucc[A <: Succ[B], B <: Nat](implicit r: RepNat[B]): RepNat[A] = new RepNat[A](r.value + 1)
println(rep[_0])
println(rep[_1])
// does not work, implicits do not resolve recursively:
// implicitly[RepNat[_2]]
// println(rep[_2])
// but explicit instantiation works:
println(rep[_2](repSucc(implicitly[RepNat[_1]])))
答案 0 :(得分:3)
递归implicits确实有效。以下定义适用于_2
:
implicit def repSucc[A <: Nat, B <: Nat](implicit
ev: A <:< Succ[B],
r: RepNat[B]
): RepNat[A] =
new RepNat[A](r.value + 1)
我相信原因是这样的
repSucc
获取单个实际类型参数A
,并需要从中计算B
。根据您的定义,它会尝试同时分配A
和B
,从而B
被有效地分配给Nothing
。
这是Scala中类型推断的常见问题,通常的解决方案是将绑定类型A <: M[B]
移动到通用类型约束A <:< M[B]
。
另请注意,隐式参数的顺序很重要:首先,编译器使用B
从A
计算ev: A <:< Succ[B]
,然后找到{{1}的RepNat
实现可能是递归的。