带参考的依赖类型(Scala)

时间:2017-02-25 03:43:36

标签: scala dependent-type path-dependent-type

我在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)

1 个答案:

答案 0 :(得分:0)

我对路径依赖类型不太熟悉,但从here我可以读到的内容来看,似乎会发生OuterouterSelf.type不一样的事情:

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

我认为你的问题来自这里,但我对此知之甚少,无法为你提供更多帮助。