2010-01-14 126 views
9

我想用a preceding question的答案來實現一個小圖庫。這個想法是考慮圖形作爲集合,其中頂點包裝集合元素。我想使用抽象類型來表示Vertex和Edge類型(因爲類型安全),我想使用類型參數來表示集合元素的類型(因爲我想在實例化中很容易定義它們)。在scala中混合類型參數和抽象類型

但是,當嘗試我能想到的最基本的例子時,我遇到了編譯錯誤。這裏是例子:

package graph 

abstract class GraphKind[T] { 

    type V <: Vertex[T] 
    type G <: Graph[T] 

    def newGraph(): G 

    abstract class Graph[T] extends Collection[T]{ 
    self: G => 
    def vertices(): List[V] 
    def add(t: T): Unit 
    def size(): Int 
    def elements(): Iterator[T] 
    } 

    trait Vertex[T] { 
    self: V => 
     def graph(): G 
     def value(): T 
    } 

} 

這裏是基本實現:

class SimpleGraphKind[T] extends GraphKind[T] { 

    type G = GraphImpl[T] 
    type V = VertexImpl[T] 

    def newGraph() = new GraphImpl[T] 

    class GraphImpl[T] extends Graph[T] { 
    private var vertices_ = List[V]() 
    def vertices = vertices_ 
    def add(t: T) { vertices_ ::= new VertexImpl[T](t,this) } 
    def size() = vertices_.size 
    def elements() = vertices.map(_.value).elements 
    } 

    class VertexImpl[T](val value: T, val graph: GraphImpl[T]) extends Vertex[T] { 
    override lazy val toString = "Vertex(" + value.toString + ")" 
    } 

} 

當嘗試編譯,我得到:

/prg/ScalaGraph/study/Graph.scala:10: error: illegal inheritance; 
self-type GraphKind.this.G does not conform to Collection[T]'s selftype Collection[T] 
    abstract class Graph[T] extends Collection[T]{ 
          ^
/prg/ScalaGraph/study/Graph.scala:33: error: illegal inheritance; 
self-type SimpleGraphKind.this.GraphImpl[T] does not conform to SimpleGraphKind.this.Graph[T]'s selftype SimpleGraphKind.this.G 
    class GraphImpl[T] extends Graph[T] { 
         ^
/prg/ScalaGraph/study/Graph.scala:36: error: type mismatch; 
found : SimpleGraphKind.this.VertexImpl[T] 
required: SimpleGraphKind.this.V 
    def add(t: T) { vertices_ ::= new VertexImpl[T](t,this) } 
           ^
/prg/ScalaGraph/study/Graph.scala:38: error: type mismatch; 
found : Iterator[T(in class SimpleGraphKind)] 
required: Iterator[T(in class GraphImpl)] 
    def elements() = vertices.map(_.value).elements 
             ^
/prg/ScalaGraph/study/Graph.scala:41: error: illegal inheritance; 
self-type SimpleGraphKind.this.VertexImpl[T] does not conform to SimpleGraphKind.this.Vertex[T]'s selftype SimpleGraphKind.this.V 
    class VertexImpl[T](val value: T, val graph: GraphImpl[T]) extends Vertex[T] { 
                   ^
5 errors found 

我絕對沒有的含義想法這些錯誤...但是,如果我在執行中專門化類型T(class SimpleGraphKind extends GraphKind[Int]我只得到第一個錯誤。)

你有什麼想法嗎?

+0

您能否說明您爲什麼要將圖表作爲集合? – 2010-01-14 19:42:47

+0

這個庫的一個應用是在圖上實現一種細胞自動機(另一個是複雜的網絡研究)。然後,直接訪問頂點中包含的Cell對象可能會更好......但如果您對解決方案沒有圖形作爲集合功能的想法,我也很感興趣。 – paradigmatic 2010-01-14 20:00:05

+0

我仍然不確定是否看到連接。您如何看待圖形庫與JGraphT的區別?它是一種圖形的功能方法嗎? – 2010-01-14 20:53:47

回答

11

編譯這與-explaintypes產量:

<console>:11: error: illegal inheritance; 
self-type GraphKind.this.G does not conform to Collection[T]'s selftype Collection[T] 
     abstract class Graph[T] extends Collection[T]{ 
             ^
    GraphKind.this.G <: Collection[T]? 
     Iterable[T] <: Iterable[T]? 
     T <: T? 
      T <: Nothing? 
      <notype> <: Nothing? 
      false 
      Any <: Nothing? 
       <notype> <: Nothing? 
       false 
      false 
      false 
      Any <: T? 
      Any <: Nothing? 
       <notype> <: Nothing? 
       false 
      false 
      false 
     false 
     false 
     GraphKind.this.Graph[T] <: Iterable[T]? 
     Iterable[T] <: Iterable[T]? 
      T <: T? 
      T <: Nothing? 
       <notype> <: Nothing? 
       false 
       Any <: Nothing? 
       <notype> <: Nothing? 
       false 
       false 
      false 
      Any <: T? 
       Any <: Nothing? 
       <notype> <: Nothing? 
       false 
       false 
      false 
      false 
     false 
     false 
    false 

現在,我正要寫我不明白怎麼T <: T可以是假的 - 這幾乎是像T兩次定義,這當然是整個問題。在這裏:

abstract class GraphKind[T] { 

    type V <: Vertex[T] 
    type G <: Graph[T] 

    def newGraph(): G 

    abstract class Graph[T] extends Collection[T]{ 

好吧,類GraphKind的參數與T並鍵入G必須是Graph[T]。現在,類Graph也被參數化,其參數也被稱爲T。爲了避免混淆,我們重寫它:

abstract class Graph[T2] extends Collection[T2]{ 
    self: G => 
    def vertices(): List[V] 
    def add(t: T2): Unit 
    def size(): Int 
    def elements(): Iterator[T2] 
    } 

請注意,這與您所寫的內容完全相等。我只是爲類型參數使用了不同的名稱,因此它不會與參數化爲GraphKindT混淆。

所以,這裏的邏輯:

G <: Graph[T] 
Graph[T2] <: Collection[T2] 
Graph[T2] <: G // self type 

這意味着

Graph[T2] <: Graph[T] 

而且,由於Graph擴展Collection

Collection[T2] <: Collection[T] 

但是沒有保證,這是真正。我不明白爲什麼在繼承不存在時不顯示問題。修復:

abstract class GraphKind[T] { 

    type V <: Vertex 
    type G <: Graph 

    def newGraph(): G 

    abstract class Graph extends Collection[T]{ 
    self: G => 
    def vertices(): List[V] 
    def add(t: T): Unit 
    def size(): Int 
    def elements(): Iterator[T] 
    } 

    trait Vertex { 
    self: V => 
     def graph(): G 
     def value(): T 
    } 

} 

class SimpleGraphKind[T] extends GraphKind[T] { 

    type G = GraphImpl 
    type V = VertexImpl 

    def newGraph() = new GraphImpl 

    class GraphImpl extends Graph { 
    private var vertices_ = List[V]() 
    def vertices = vertices_ 
    def add(t: T) { vertices_ ::= new VertexImpl(t,this) } 
    override def size() = vertices_.size 
    override def elements() = vertices.map(_.value).elements 
    } 

    class VertexImpl(val value: T, val graph: GraphImpl) extends Vertex { 
    override lazy val toString = "Vertex(" + value.toString + ")" 
    } 
} 

由於VertexGraph將被捆綁到一個GraphKind實例,那麼T將固定爲不管它是爲實例定義。例如:

scala> new SimpleGraphKind[Int] 
res0: SimpleGraphKind[Int] = [email protected] 

scala> new res0.GraphImpl 
res1: res0.GraphImpl = line10() 

scala> res1.add(10) 

scala> res1.add("abc") 
<console>:9: error: type mismatch; 
found : java.lang.String("abc") 
required: Int 
     res1.add("abc") 
       ^
+0

非常感謝。我必須承認我很慚愧,因爲我在5年前在java中學習泛型時遇到了類似的錯誤... – paradigmatic 2010-01-15 06:59:05

+1

沒有必要慚愧,我也這樣做,然後恨自己這樣做,並不是我不知道它是如何工作的,只是寫'D [T]擴展C [T]'是自然的。 – 2010-01-15 17:51:39

+0

另一方面,'-explaintypes'是你的朋友,需要一段時間才能適應它,特別是當它們從一個co-variant跳轉到contra-variant時會被切換。它適用於複雜類型的錯誤。 – 2010-01-17 16:11:37

1

似乎頂點屬於一個特定的圖形,只有該圖形可以在圖形中具有嵌套的頂點特徵的類型系統中表現得最好。你試圖達到什麼樣的結構?

abstract class Graph[T] extends Collection[T] { 
    thisGraph: Graph[T] => 

    def newGraph: Graph[T] 
    def vertices: List[Vertex[T]] 
    def add(t: T): Unit 
    def size: Int 
    def elements: Iterator[T] 

    trait Vertex[T] { 
     def graph = thisGraph 
     def value: T 
    } 
} 

class SimpleGraph[T] extends Graph[T] { 
    private[this] var verts = List[Vertex[T]]() 

    def newGraph = new SimpleGraph[T] 
    def vertices = verts 
    def add(t: T) { verts ::= SimpleVertex(t) } 
    override def size = verts.size 
    override def elements = verts.map(_.value).elements 
    def iterator = elements // the "new" elements in 2.8 

    case class SimpleVertex[T](value: T) extends Vertex[T] 
}