【问题标题】:Creating a parametric graph type in Scala在 Scala 中创建参数图类型
【发布时间】:2010-10-06 22:08:14
【问题描述】:

我想创建一个通用类型层次结构来表示图形。特别是,我想要类 Graph 和 Node,并且我希望每个 Graph 类型都有一个相应的 Node 类型,如果我创建一个用于操作 Graphs 的通用函数,我希望这个函数使用实际的 Node类型。我试过的一个例子

trait GNode[Graph]
{
 ... functions to get edges from this vertex, etc. ...
}

trait Graph
{
  type Node <: GNode[Graph]
}

def dfs[G <: Graph](g : G, nodeAction : G#Node => Unit) = ... code ...

但这不起作用,因为当我这样做时

class ConcreteGraph extends Graph
{
  class Node extends GNode[ConcreteGraph] { ... }
}

dfs 函数不接受 ConcreteGraph#Node=&gt;Unit 类型的函数为 nodeAction,而只接受 AnyRef=&gt;UnitGNode[ConcreteGraph]=&gt;Unit

为了更清楚,如果我用 C++ 做,我会做类似的事情

template <class T> struct graph_traits;
template <> struct graph_traits<concrete_graph> 
{ typedef concrete_graph::node node_type; }

template <class G>
void dfs(const G& g, boost::function<void(
           const graph_traits<G>::node_type&)> action) { ... }

【问题讨论】:

    标签: generics scala graph types


    【解决方案1】:

    可扩展图结构的一个很好的例子是 http://www.scala-lang.org/node/124

    我有你写你的方法。请注意,在所有情况下都需要进行一些类型更改 - 即 GNode 的类型参数需要是协变的,并且 ConcreteGraph 需要使用不同的节点类和 Node 绑定的类型来编写。

    一旦完成,编写 dfs 的第一种方法是使其成为一个方法(如果你想避免虚拟调度开销,它可以是最终的)。

    trait GNode[+Graph] {
    //... functions to get edges from this vertex, etc. ...
    }
    
    trait Graph {
      type Node <: GNode[Graph]
    
      def dfs(nodeAction : Node => Unit) = print("dfsing!")
    }
    
    class ConcreteGraph extends Graph {
      class CGNode extends GNode[ConcreteGraph]
      type Node <: CGNode
    }
    
    new ConcreteGraph dfs {node => println("foo")}
    

    第二个,dfs 不是方法,似乎只需要一点额外的类型提示就可以使用它。

    def dfs[G <: Graph](graph : G, nodeAction : G#Node => Unit) = print("dfsing!")
    
    dfs[ConcreteGraph](new ConcreteGraph, {node => println("foo")})
    

    第三种方法是使用咖喱 dfs。由于 Scala 的类型推断的工作方式,这实际上导致了更简洁的界面

    def dfs[G <: Graph](graph : G)(nodeAction : G#Node => Unit) = print("dfsing!")
    
    dfs(new ConcreteGraph){node => println("foo")}
    

    【讨论】:

    • 谢谢。但是,我不确定为什么需要在 ConcreteGraph 中执行 CGNode 类和类型 Node。我创建了一个小例子:snipt.org/vpk,它对我来说似乎很实用
    • 还有一个:在这个例子中,我可以将 dfs 限制为那些类型 G,其节点类型是 <: ordered>
    【解决方案2】:

    我不明白为什么所有这些参数都是必需的。 Scala 中的内部类(与 Java 不同)具有依赖于外部对象的特定实例的类型。特别是:

    trait Graph {
      trait Node
      def dfs(n: Node) = println("DFSing!")
    }
    
    val graphA = new Graph {}
    val nodeA = new graphA.Node {}
    val graphB = new Graph {}
    val nodeB = new graphB.Node {}
    graphA.dfs(nodaA)  // prints "DFSing!"
    graphB.dfs(nodeB)  // prints "DFSing!"
    graphA.dfs(nodeB)  // type mismatch; found: graphB.Node required: graphA.Node
    graphB.dfs(nodeA)  // type mismatch; found: graphA.node required: graphB.Node
    

    当然,如果您想依赖依赖类型,则不能在图形之外定义 dfs。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-09-25
      • 1970-01-01
      • 1970-01-01
      • 2021-07-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多