2016-11-19 78 views
2

我想打印皮亞諾的數字,這樣的事情:有沒有辦法用類型做遞歸隱式def?

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]]))) 

回答

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]

另外,還要注意的隱含參數的順序很重要:第一,編譯器從A計算Bev: A <:< Succ[B],然後找到RepNat實施B,可能是遞歸。

相關問題