返回路径依赖类型

时间:2011-07-20 22:53:01

标签: scala path-dependent-type

如何设计返回路径依赖类型的方法?在下面的示例中,我故意希望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 个答案:

答案 0 :(得分: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 :(得分:1)

我认为您可以使用-Xexperimental -Ydependent-method-types为依赖方法类型启用实验支持。

答案 2 :(得分: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)
  }
}