我在斯卡拉玩(路徑)依賴類型和偶然發現以下情況,我找不到一個好的解決方案。 假設我想擁有一些依賴類型的層次結構,並且我希望他們每個人都有一個引用返回到它的「所有者」對象。我希望這個反向引用能夠在正確的「所有者」對象上調用某些方法。什麼是正確的方法來做到這一點?依賴類型與參考(斯卡拉)
這是一個小例子。有一個「基本」性狀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
對象和「所有者」對象又名outerSelf
的outer
領域是同樣的事情,有時沒有,它是不清楚如何說服編譯器時它不承認它們是同一件事。
有沒有辦法解決這個問題?或者這是對我的問題完全錯誤的方法? (顯然在現實世界中,我想創建不只是愚蠢的代理,如DepTest.double
,但一些更高級功能的庫,如multiplyByPow2(val : Outer#Inner, exponent: Int)
)