2017-02-25 203 views
1

我在斯卡拉玩(路徑)依賴類型和偶然發現以下情況,我找不到一個好的解決方案。 假設我想擁有一些依賴類型的層次結構,並且我希望他們每個人都有一個引用返回到它的「所有者」對象。我希望這個反向引用能夠在正確的「所有者」對象上調用某些方法。什麼是正確的方法來做到這一點?依賴類型與參考(斯卡拉)

這是一個小例子。有一個「基本」性狀Outer與依賴類型Inner。基礎Outer特徵定義了對依賴類型起作用的一些方法double。還有一個特定的類ConcreteOuter與特定的相關類ConcreteInner,該值使用簡單的Int

trait Outer { 
    outerSelf => 

    trait BaseInner { 
    val outer: outerSelf.type = outerSelf 

    def asDependent: outer.Inner   // #1 
    // def asDependent: outerSelf.Inner // #2 
    } 

    type Inner <: BaseInner 

    def double(inner: Inner): Inner 
} 

class ConcreteOuter extends Outer { 
    case class ConcreteInner(val v: Int) extends BaseInner { 
    override def asDependent = this  
    } 

    type Inner = ConcreteInner 

    def createInner(v: Int): Inner = new ConcreteInner(v) 

    override def double(inner: Inner): Inner = new ConcreteInner(2 * inner.v) 
} 

到目前爲止好。現在假設我希望能夠在僅有某個Inner類的實例但不包含對應的Outer-實例的情況下調用該方法double。例如,讓我們嘗試創建另一個double方法只是調用其他一些(獨立的)背景下,原有的Outer.double

object DepTest extends App { 

    //def double(inner: Outer#Inner) = inner.outer.double(inner)   // #3 

    def double(inner: Outer#Inner) = inner.outer.double(inner.asDependent) // #4 


    val c1 = new ConcreteOuter 
    val i1 = c1.createInner(123) 
    val d1 = double(i1) 
    println(d1) 

} 

此代碼編譯,但需要的asDependent相當醜陋的黑客。如果我使用第3行而不是第4行,則代碼不會編譯。如果我在下面的方式分割線#3的代碼不編譯了

def double(inner: Outer#Inner) = { 
    val outer = inner.outer 
    outer.double(inner.asDependent) 
    } 

而且,如果我更換線#1線#2連asDependent黑客停止工作。

所以看起來莫名其妙有時編譯器知道Inner對象和「所有者」對象又名outerSelfouter領域是同樣的事情,有時沒有,它是不清楚如何說服編譯器時它不承認它們是同一件事。

有沒有辦法解決這個問題?或者這是對我的問題完全錯誤的方法? (顯然在現實世界中,我想創建不只是愚蠢的代理,如DepTest.double,但一些更高級功能的庫,如multiplyByPow2(val : Outer#Inner, exponent: Int)

回答

0

我不是很有經驗的路徑依賴類型,但從我可以從here看,似乎有什麼情況是,OuterouterSelf.type是不一樣的東西:

  • outerSelf.type包括以下任outerSelfnull
  • outerSelf: Outer只包含outerSelf

我覺得你的問題來自這裏,但我對這方面的知識還不夠多,能夠幫助你更多。