带有参考返回(Scala)的相关类型



我正在使用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)

我对路径依赖类型不是很有经验,但是从这里我可以阅读的内容,似乎会发生OuterouterSelf.type不是同一件事:

  • outerSelf.typeouterSelfnull
  • 组成
  • outerSelf: Outer仅由outerSelf
  • 组成

我认为您的问题来自这里,但是我对此没有足够的了解,无法为您提供更多帮助。

最新更新