我在斯卡拉玩(路径)依赖类型和偶然发现以下情况,我找不到一个好的解决方案。 假设我想拥有一些依赖类型的层次结构,并且我希望他们每个人都有一个引用返回到它的“所有者”对象。我希望这个反向引用能够在正确的“所有者”对象上调用某些方法。什么是正确的方法来做到这一点?依赖类型与参考(斯卡拉)
这是一个小例子。有一个“基本”性状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)
)