2017-02-25 159 views
1

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

这是一个小例子。有一个“基本”性状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对象和“所有者”对象又名outerSelfouter领域是同样的事情,有时没有,它是不清楚如何说服编译器时它不承认它们是同一件事。

有没有办法解决这个问题?或者这是对我的问题完全错误的方法? (显然在现实世界中,我想创建不只是愚蠢的代理,如DepTest.double,但一些更高级功能的库,如multiplyByPow2(val : Outer#Inner, exponent: Int)

回答

0

我不是很有经验的路径依赖类型,但从我可以从here看,似乎有什么情况是,OuterouterSelf.type是不一样的东西:

  • outerSelf.type包括以下任outerSelfnull
  • outerSelf: Outer只包含outerSelf

我觉得你的问题来自这里,但我对这方面的知识还不够多,能够帮助你更多。