有没有办法用类型进行递归隐式def?

时间:2016-11-19 07:33:11

标签: scala

我正在尝试打印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]])))

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。根据您的定义,它会尝试同时分配AB,从而B被有效地分配给Nothing

这是Scala中类型推断的常见问题,通常的解决方案是将绑定类型A <: M[B]移动到通用类型约束A <:< M[B]

另请注意,隐式参数的顺序很重要:首先,编译器使用BA计算ev: A <:< Succ[B],然后找到{{1}的RepNat实现可能是递归的。