【问题标题】:Scala fails to infer the right type argumentsScala 无法推断出正确的类型参数
【发布时间】:2011-10-16 10:05:12
【问题描述】:

背景信息:我目前正在尝试建立一个通用图形库,其中包含一些不同的搜索算法(我从 Dijkstra 开始)。我设置了一些特征来表示可以在某些类型的图表中找到的方法(例如加权、有向):

trait GraphOps[V,E] { ... }
trait WeightedGraphOps[V,E] extends GraphOps[V,E] { ... }
trait DirectedGraphOps[V,E] extends GraphOps[V,E] { ... }
object GraphOps{
  def Dijkstra[V,E,G <: WeightedGraphOps[V,E] with DirectedGraphOps[V,E]](graph:G, start:V) = { ... }
}

在其他地方,我有一个类作为我想在其上运行 Dijkstra 算法的加权有向图的具体实现:

class GraphMap[T](...)
extends scala.collection.mutable.Map[Position,T]
with WeightedGraphOps[Position,Edge] with DirectedGraphOps[Position,Edge] { ... }

但是当我尝试测试它时:

val graph = new GraphMap[Int](...)
val (dist, prev) = GraphOps.Dijkstra(graph, Position(0,0))

问题:我在编译时收到以下错误:error: inferred type arguments [com.dylan.data.Position,Nothing,com.dylan.data.GraphMap[Int]] do not conform to method Dijkstra's type parameter bounds [V,E,G &lt;: com.dylan.data.WeightedGraphOps[V,E] with com.dylan.data.DirectedGraphOps[V,E]]
我花了很长时间才注意到它推断我的 Edge (E) 类型为Nothing,但我不明白为什么它无法成功推断它应该是Edge。为什么它无法推断出该类型参数,我该如何解决?

附:我尝试执行以下操作,并让它工作,但这对于应该是一种方便的方法来说似乎非常不方便:

type Helpful = WeightedGraphOps[Position,Edge] with DirectedGraphOps[Position,Edge]
val (dist, prev) = GraphOps.Dijkstra[Position,Edge,Helpful](graph, Position(0,0))

【问题讨论】:

  • 您确实意识到已经有一个图形库,不是吗?
  • 因为我这样做是出于业余爱好,而且由于几分钟的搜索并没有得出明确的答案,我想我不妨自己整理一下。
  • 我很好奇你到底用什么词谷歌?我尝试了 'scala graph library' 并得到了这个:code.google.com/p/scala-graphs 这不是给你的吗?
  • 那个项目没有下载也没有源代码。我搜索了那个确切的术语并确实找到了,以及 StackOverflow 问题中提到它已经死了。
  • 下面链接的图形库正在积极开发中,希望被包含在 Scala 集合库中。发行说明和路线图看起来很有希望。 assembla.com/spaces/scala-graph/wiki

标签: generics scala generic-type-argument


【解决方案1】:

Daniel 可能是对的,现有的 Scala 类型推断器需要更直接的信息来确定 E 必须是 Edge。此外,据我了解,类型推断是故意未指定的,以便为未来的改进让路。

无论如何,我认为您可以采用另一种设计方法来解决类型推断问题:使用类型 members 而不是参数。我已经用下面的自包含代码说明了我的意思。关键思想是EV 类型成为GraphOps 类型的一部分,但它们仍然可以通过使用类型细化 以类型参数的形式出现,如Dijkstra方法。

trait GraphOps { type E; type V }
trait WeightedGraphOps extends GraphOps { }
trait DirectedGraphOps extends GraphOps { }
object GraphOps{
  def Dijkstra[V0, G <: (WeightedGraphOps{type V = V0})
                         with (DirectedGraphOps{type V = V0})]
      (graph:G, start:V0) = { }
}

case class Position(x: Int, y: Int)
case class Edge()

case class GraphMap[T]() extends WeightedGraphOps with DirectedGraphOps {
  type E = Edge
  type V = Position
}

object Test {
  val graph = new GraphMap[Int]( )
  GraphOps.Dijkstra(graph, Position(0,0))
}

编辑 这种类型成员方法的一个潜在限制是在方法Dijkstra 中对类型参数G 的约束较少。具体来说,边界WeightedGraphOpsDirectedGraphOps 不限于具有相同类型的成员E。我不确定如何在不遇到您最初报告的类型推断问题的情况下解决此问题。一种方法是这个问题中的模式:Why do these type arguments not conform to a type refinement?,但似乎 Scala 编译器无法处理它。

Edit2 忽略以上段落。正如 Dylan 在 cmets 中提到的,对于这种 diamond inheritance 情况,Scala 很好地确保了类型 E 的一致性。例如,以下编译正常:

trait GraphOps { type E; type V }
trait WeightedGraphOps extends GraphOps { def f(e: E) }
trait DirectedGraphOps extends GraphOps { def e: E }
object GraphOps{
  def Dijkstra[V0, G <: (WeightedGraphOps{type V = V0}) with (DirectedGraphOps{type V = V0})] (graph:G, start:V0) = {
    graph.f(graph.e)
  }
}

【讨论】:

  • 这对我有帮助,谢谢!我不确定我是否应该担心缺少边缘类型约束——我可能遗漏了一些东西,但我无法创建一个混合两种 Ops 类型但具有不同 E 类型的对象。有可能吗?
  • 有趣。这听起来像是类型的钻石问题(en.wikipedia.org/wiki/Diamond_problem)。对于值,Scala 对菱形问题的解决方案是基于线性化方案,一个值覆盖另一个值。对于类型,为了避免不一致而不允许这样做,我并不感到惊讶。
【解决方案2】:

为什么它应该是Edge?如果您查看Dijkstra 的声明,您会发现没有任何参数引用E(graph:G, start:V)。所以 Scala 知道G 应该是什么,V 应该是什么。没有参数引用E

【讨论】:

  • 但是一个足够聪明的 Scala 编译器不能在这个调用站点上解决它吗?知道graph 具有WeightedGraphOps[Position, Edge] with ... 类型基本上可以解决E 必须使类型工作的问题。
  • 它应该是Edge,因为这是 GraphMap 中边的类型。 Dijkstra 的实现需要类型,所以我不能把它省略。
  • @Dylan 我知道您有问题,我只是想让您更好地理解类型推断约束,这样您就可以更轻松地编写代码。这里的问题是:类型是从参数中推断出来的。 G 是从 graph 推断出来的。应该从中推断出参数E 是什么?它不会从类型约束中推断出来——这只是它被检查的内容,它是从中推断出来的。
  • 我明白了,假设我的方法签名是(graph:G, start:V, edgesToExclude:E*);只要我用一些边列表调用该方法,推理就应该成功,但是如果我在不排除任何边的情况下调用它,我仍然会遇到和以前一样的问题,对吗?
  • @Dylan 请参阅this question 了解解决问题的方法——基本上,参数化G 以便EV 可以附加到参数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-08
  • 1970-01-01
  • 1970-01-01
  • 2018-08-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多