我正在使用Scala中的(路径 - )依赖类型玩,并且偶然发现了以下情况,我找不到一个很好的解决方案。假设我想拥有一些因类型的层次结构,我希望他们每个人都会引用其"所有者"对象。我希望这种反引用能够在正确的"所有者"对象上调用一些方法。正确的方法是什么?
这是一个小例子。有一个"基础"特质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
-INCANE的上下文中调用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
hack停止工作。
因此,看起来有时候编译器有时知道Inner
对象的outer
字段和"所有者"对象AKA outerSelf
是同一件事,有时却不是,并且尚不清楚如何说服编译器时如何说服编译器。不认为它们是同一件事。
有没有办法解决这个问题?还是这是我问题完全错误的方法?(显然,在现实世界中,我不仅要创建诸如DepTest.double
之类的愚蠢代理,还要创建一些高级功能的库,例如multiplyByPow2(val : Outer#Inner, exponent: Int)
)
我对路径依赖类型不是很有经验,但是从这里我可以阅读的内容,似乎会发生Outer
和outerSelf.type
不是同一件事:
-
outerSelf.type
由outerSelf
或null
组成 -
outerSelf: Outer
仅由outerSelf
组成
我认为您的问题来自这里,但是我对此没有足够的了解,无法为您提供更多帮助。