Generics Scala无法推断正确的类型参数

Generics Scala无法推断正确的类型参数,generics,scala,generic-type-argument,Generics,Scala,Generic Type Argument,背景信息:我目前正在尝试建立一个通用图形库,其中包含一些不同的搜索算法(我从Dijkstra的开始)。我设置了一些特性来表示在某些类型的图(例如加权图、定向图)中可以找到的方法: 但当我尝试测试它时: val graph = new GraphMap[Int](...) val (dist, prev) = GraphOps.Dijkstra(graph, Position(0,0)) 问题:我在编译过程中遇到以下错误:错误:推断的类型参数[com.dylan.data.Position,No

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

但当我尝试测试它时:

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

问题:我在编译过程中遇到以下错误:
错误:推断的类型参数[com.dylan.data.Position,Nothing,com.dylan.data.GraphMap[Int]]不符合方法Dijkstra的类型参数边界[V,E,G为什么它应该是
Edge
?如果你看
Dijkstra
的声明,你会发现没有一个参数引用
E
(图:G,开始:V)
。因此Scala有一个线索,即
G
应该是什么,以及
V
应该是什么。没有任何参数引用
E

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

无论如何,我认为您可以采用另一种方法来解决类型推断问题:使用类型成员而不是参数。我已经在下面用自包含代码说明了我的意思。关键思想是类型
E
V
成为
graphhops
类型的一部分,但它们仍然可以是表面的d通过使用类型细化作为类型参数,如在
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))
}

你知道已经有一个图形库了,不是吗?因为我这样做是出于爱好,而且由于几分钟的搜索并没有得到一个明确的答案,我想我还是把自己的放在一起吧。我很好奇你到底用谷歌搜索了什么词?我试过“scala图形库”,得到了这样一个结论:这不是为你做的吗?那个项目已经有no下载,没有源代码。我搜索了这个确切的术语,确实发现了它,还有StackOverflow问题提到它已经死了。下面链接的图形库正在积极开发中,希望能包含在Scala collections库中。发行说明和路线图看起来很有希望。但这还不够聪明Scala编译器在这个调用站点上找到了答案?知道
graph
具有类型
WeightedGraphOps[Position,Edge]使用…
基本上修复了
E
必须具备的使类型工作的功能。它应该是
Edge
,因为这是图形映射中的边类型。Dijkstra的实现需要类型,所以我不能忽略它。@Dylan我知道你有问题,我只是想让你理解inf类型引用约束更好,因此您可以更轻松地编写代码。这里的问题是:类型是从参数推断出来的。
G
是从
graph
推断出来的。参数
E
应该从何处推断出来?它不会从类型约束中推断出来——这只是它被检查的对象,它是什么从中推断。我明白了,所以让我们假设我的方法签名是
(图:G,开始:V,edgesToExclude:E*)
;只要我调用带有一些边列表的方法,推理应该会成功,但是如果我调用它时没有排除任何边,我仍然会遇到与以前相同的问题,对吗?@Dylan想找到解决问题的方法——基本上,参数化
G
,这样
E
V
就可以附加到参数上r、 这帮了我的忙,谢谢!我不确定是否应该担心缺少边缘类型约束-我可能遗漏了一些东西,但我无法创建一个混合了两种Ops类型但具有不同
E
类型的对象。这可能吗?有趣。听起来像钻石问题()对于类型。对于值,Scala对菱形问题的解决方案是,基于线性化方案,一个值优先于另一个值。对于类型,为了避免不一致,不允许这样做并不奇怪。
val graph = new GraphMap[Int](...)
val (dist, prev) = GraphOps.Dijkstra(graph, Position(0,0))
type Helpful = WeightedGraphOps[Position,Edge] with DirectedGraphOps[Position,Edge]
val (dist, prev) = GraphOps.Dijkstra[Position,Edge,Helpful](graph, Position(0,0))
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))
}
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)
  }
}