我在Scala中使用(路径)依赖类型,偶然发现了一个我无法找到解决方案的情况。 假设我想要一些依赖类型的层次结构,并且我希望它们中的每一个都有一个返回其“owner”对象的引用。我希望这个反向引用能够在正确的“所有者”对象上调用一些方法。这样做的正确方法是什么?
这是一个小例子。存在具有依赖类型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)
}
到目前为止一切顺利。现在假设我希望能够在我只有一些double
类但不是相应的Inner
- 实例的实例的上下文中调用Outer
方法。例如,让我们尝试创建另一个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)
}
此外,如果我用第2行代替第1行,即使asDependent
黑客停止工作。
所以看起来有时编译器知道outer
对象的Inner
字段和{owner}对象outerSelf
是同一个东西,有时它不会并且不清楚如何在编译器不能识别它们时说服编译器。
有没有办法解决这个问题?或者这对我的问题是一个完全错误的方法? (显然在现实世界中,我不仅要创建像DepTest.double
这样的哑代理,而是创建一些更高级别的函数库,例如multiplyByPow2(val : Outer#Inner, exponent: Int)
)
答案 0 :(得分:0)
我对路径依赖类型不太熟悉,但从here我可以读到的内容来看,似乎会发生Outer
和outerSelf.type
不一样的事情:
outerSelf.type
由outerSelf
或null
outerSelf: Outer
仅由outerSelf
我认为你的问题来自这里,但我对此知之甚少,无法为你提供更多帮助。