【问题标题】:Returning a path-dependent type返回依赖于路径的类型
【发布时间】:2013-09-28 03:33:26
【问题描述】:

如何设计一个返回路径相关类型的方法?在下面的示例中,我故意希望 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"

【问题讨论】:

    标签: scala path-dependent-type


    【解决方案1】:

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

    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
      }
    }
    

    【讨论】:

    • 如果您对使用 -Ydependent-method-types 不满意,那么我会推荐这个(将依赖值与依赖类型打包)。
    • 谢谢你,这行得通。因为,正如我所想,你不需要-Xexperimental,我想知道为什么必须显式启用它?
    【解决方案2】:

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

    【讨论】:

    • 谢谢,确实有效(你只需要-Ydependent-method-types
    • 这个标志需要什么版本的 Scala?我在 Scala 2.10.3 中得到“错误选项:'-Ydependent-method-types'”。
    • 现在默认启用依赖类型。
    【解决方案3】:

    我不太了解类型系统,无法解释为什么您的第一次尝试不起作用,但这是我通常遵循的模式(使用有界抽象类型成员),它确实可以编译。很高兴看到 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)
      }
    }
    

    【讨论】:

    • 在我的具体情况下,顶点与排序相关联,我希望将每个排序限制为与从同一排序中检索到的元素进行比较。排序维护一个Int 标签,所以从技术上讲,混合排序没有问题;路径相关类型提供了一种防止这种情况发生的好方法,因为跨排序(或此处的树)进行比较几乎肯定是一个错误。事实上,在我让我的代码工作(以 gagaism 方式)之后,编译器确实找到了至少一个地方我犯了那个确切的错误。是对这种方法的一种很好的确认
    猜你喜欢
    • 2014-09-07
    • 1970-01-01
    • 2016-06-03
    • 1970-01-01
    • 1970-01-01
    • 2013-04-17
    • 1970-01-01
    • 1970-01-01
    • 2016-06-04
    相关资源
    最近更新 更多