2011-07-20 37 views
4

如何设计返回路径依赖类型的方法?在下面的例子中,我特意要Vertex是路径依赖Tree使得它被禁止混合整个树的顶点(这只是一个例子):返回路径依赖类型

trait Tree { 
    trait Vertex 
    def root: Vertex 
    def addChild(parent: Vertex): Vertex 
} 

trait TreeFactory { def make: Tree } 

现在无法构造如下:

def test(f: TreeFactory): (Tree, Map[Tree#Vertex, Tree#Vertex]) = { 
    val t = f.make 
    var sq = IndexedSeq(t.root) 
    var m = Map.empty[t.Vertex, t.Vertex] 
    for(i <- 1 to 100) { 
    val p = sq(util.Random.nextInt(sq.size)) 
    val c = t.addChild(p) 
    m += c -> p 
    sq :+= c 
    } 
    (t, m) 
} 

因为显然地图我回应该不会有按键和Tree#Vertex类型,但路径依赖的顶点值...

error: type mismatch; 
found : scala.collection.immutable.Map[t.Vertex,t.Vertex] 
required: Map[Tree#Vertex,Tree#Vertex] 
Note: t.Vertex <: Tree#Vertex, but trait Map is invariant in type A. 
You may wish to investigate a wildcard type such as `_ <: Tree#Vertex`. (SLS 3.2.10) 
      (t, m) 
      ^

如果我尝试去耦树创建和亲子地图积聚:

def test(t: Tree): Map[t.Vertex, t.Vertex] = { 
    var sq = IndexedSeq(t.root) 
    var m = Map.empty[t.Vertex, t.Vertex] 
    for (i <- 1 to 100) { 
    val p = sq(util.Random.nextInt(sq.size)) 
    val c = t.addChild(p) 
    m += c -> p 
    sq :+= c 
    } 
    m 
} 

这失败的另一个原因是:"error: illegal dependent method type"

回答

3

我的扭曲的心灵想出了这一个。我希望有一个更优雅的解决方案:

trait Gagaism { 
    val tree: Tree 
    val map: Map[tree.Vertex, tree.Vertex] 
} 

def test(f: TreeFactory) = new Gagaism { 
    val tree = f.make 
    val map = { 
    var sq = IndexedSeq(tree.root) 
    var m = Map.empty[tree.Vertex, tree.Vertex] 
    for (i <- 1 to 100) { 
     val p = sq(util.Random.nextInt(sq.size)) 
     val c = tree.addChild(p) 
     m += c -> p 
     sq :+= c 
    } 
    m 
    } 
} 
+1

如果你不喜欢使用-Ydependent-method-types,那么这(把依赖的值与依赖类型打包在一起)就是我所推荐的。 –

+0

谢谢你哩,这工作。因为,正如我的想法,你不需要'-X实验',我想知道为什么必须明确地启用它? –

0

我不明白的类型系统不够好解释为什么你的第一次尝试是不行的,但是这是我的图案通常遵循(有界抽象类型成员),它编译。不过,看到TreeTreeFactory的实现会更加自信。

package trees 

trait Tree { 
    trait Vertex 

    type V <: Vertex 
    def root: V 
    def addChild(parent: V): V 
} 

trait TreeFactory { def make : Tree } 

object Test { 
    def test(f: TreeFactory): (Tree, Map[Tree#Vertex, Tree#Vertex]) = { 
    val t = f.make 
    var sq = IndexedSeq(t.root) 
    var m = Map.empty[t.Vertex, t.Vertex] 
    for (i <- 1 to 100) { 
     val p = sq(util.Random.nextInt(sq.size)) 
     val c = t.addChild(p) 
     m += c -> p 
     sq :+= c 
    } 
    (t, m) 
    } 
} 
+1

在我的具体情况中,顶点与排序相关联,我想限制每个排序与从相同排序中检索的元素相比较。顺序保持一个'Int'标签,所以在技术上混合顺序没有任何问题;依赖于路径的类型提供了一个很好的方法来防止这种情况的发生,因为跨越排序(或者这里的树)的比较几乎肯定是一个错误。事实上,在我的代码工作之后(编译方式),编译器确实发现至少有一个地方犯了这个错误。对这种方法有很好的确认 –

1

你能使用-Xexperimental -Ydependent-method-types供养方法类型的实验支持,我想。

+0

谢谢,确实有效(你只需要'-Ydependent-method-types') –

+0

你需要这个标志的什么版本的Scala?我用Scala 2.10.3得到了“糟糕的选择:'-Ydependent-method-types'”。 – rightfold

+0

相关类型现在默认启用。 –