在scala中混合类型参数和抽象类型 [英] Mixing type parameters and abstract types in scala

查看:150
本文介绍了在scala中混合类型参数和抽象类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试使用前面的问题的答案来实施一个小图库。我们的想法是将图形看作colections,顶点包装集合元素。



我想使用抽象类型来表示Vertex和Edge类型(因为类型安全)和我想使用类型参数来表示集合元素的类型(因为我想在实例化时很容易地定义它们)。然而,当尝试最基本的示例I可以想一想,我遇到了编译错误。下面是例子:

 包图

抽象类GraphKind [T] {

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

def newGraph():G

抽象类图表[T]扩展集合[T] {
self:G =>
def vertices():List [V]
def add(t:T):单位
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; 
自我类型GraphKind.this.G不符合Collection [T]的自定义集合[T]
抽象类图形[T]扩展集合[T] {
^
/prg/ScalaGraph/study/Graph.scala:33:错误:非法继承;
self-type SimpleGraphKind.this.GraphImpl [T]不符合SimpleGraphKind.this.Graph [T]的自我类型SimpleGraphKind.this.G
class GraphImpl [T] extends Graph [T] {
^
/prg/ScalaGraph/study/Graph.scala:36:error:type mismatch; 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:错误:非法继承;
自我类型SimpleGraphKind.this.VertexImpl [T]不符合SimpleGraphKind.this.Vertex [T]的自我类型SimpleGraphKind.this.V
类VertexImpl [T](val值:T, val graph:GraphImpl [T])extends Vertex [T] {
^
找到5个错误

我完全不知道这些错误的含义......但是,如果我在实现中专门化类型T( class SimpleGraphKind extends GraphKind [Int] 我只得到第一个错误。



你有什么想法吗?

解决方案

使用 -explaintypes 编译此结果:

 < console>:11:error:非法继承; 
自我类型GraphKind.this.G不符合Collection [T]的自定义集合[T]
抽象类Graph [T] extends Collection [ T] {
^
图表Kind.this.G<:收集[T]?
Iterable [T] <:Iterable [T]?
T <:T?
T <:什么都没有?
< notype> <:什么都没有?
false
任何<:无?
< notype> <:什么都没有?
false
false
false
任何<:T?
任何<:没有?
< notype> <:什么都没有?
false
false
false
false
false
GraphKind.this.Graph [T]<:Iterable [T]?
Iterable [T] <:Iterable [T]?
T <:T?
T <:什么都没有?
< notype> <:什么都没有?
false
任何<:无?
< notype> <:什么都没有?
false
false
false
任何<:T?
任何<:没有?
< notype> <:什么都没有?
false
false
false
false
false
false
false

现在,我正要写我不明白 T <:T 可以如何假 - 它几乎就像 T 被定义了两次,当然这是整个问题。这里:

 抽象类GraphKind [T] {

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

def newGraph():G

抽象类Graph [T]扩展Collection [T] {

好的,类 GraphKind 被参数化为 T 和类型 G 必须是图形[T] 。现在,类 Graph 也被参数化,其参数也被称为 T 。为避免混淆,我们重写它:

 抽象类图[T2]扩展了Collection [T2] {
self: G =>
def vertices():List [V]
def add(t:T2):单位
def size():Int
def elements():Iterator [T2]
}

请注意,这与您所写的完全相同。我只是为类型参数使用了一个不同的名称,所以它不会与参数化 GraphKind T 混淆。

所以,这里是逻辑: > G <:图表[T]
图表[T2] <:集合[T2]
图表[T2] <:G //自我类型



这意味着

pre $ 图[T2] <:Graph [T]

而且,因为扩展集合

 集合[T2]<:集合[T] 

但不能保证这是真的。我不明白为什么在继承不存在时不显示问题。 Fix:

 抽象类GraphKind [T] {

类型V <:顶点
类型G <:图形

def newGraph():G

抽象类Graph扩展Collection [T] {
self:G =>
def vertices():List [V]
def add(t:T):单位
def size():Int
def elements():Iterator [T]
}

特征顶点{
self:V =>
def graph():G
def value():T
}

}

class SimpleGraphKind [T]扩展GraphKind [ T] {

type G = GraphImpl
type V = VertexImpl

def newGraph()= new GraphImpl

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

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

由于顶点会绑定到 GraphKind 的一个实例,然后 T 将被固定为针对该实例定义的任何实例。例如:

  scala> new SimpleGraphKind [Int] 
res0:SimpleGraphKind [Int] = SimpleGraphKind @ 1dd0fe7

scala>新的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)
^


I am trying to use the answer of a preceding question to implement a small graph library. The idea is to consider graphs as colections, where vertices wrap collection elements.

I would like to use abstract types to represent Vertex and Edge types (because of type safety) and I want to use type parameters to represent the type of the collection elements (because I want to define them at instantiation easily).

However, when trying the most basic example I can think about, I am stuck with compile errors. Here is the example:

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
  }

}

And here is the basic implementations:

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 + ")"
  }

}

When trying to compile, I get:

/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

I have absolutely no idea of the meaning of these errors... However, if I specialize the type T in the implementation (class SimpleGraphKind extends GraphKind[Int] I get only the first error.

Do you have some ideas ?

解决方案

Compiling this with -explaintypes yields:

<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

Now, I was about to write I don't understand how T <: T can be false -- it is almost like T was defined twice, which, of course, is the whole problem. Here:

abstract class GraphKind[T] { 

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

  def newGraph(): G 

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

Ok, class GraphKind is parameterized with T and type G must be a Graph[T]. Now, class Graph is also parameterized, and its parameter is also called T. To prevent confusing, let's rewrite it:

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

Note that this is EXACTLY EQUAL to what you wrote. I'm just using a different name for the type parameter, so that it doesn't get confused with the T that is parameterizing GraphKind.

So, here is the logic:

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

which implies that

Graph[T2] <: Graph[T]

And, because Graph extends Collection:

Collection[T2] <: Collection[T]

But there is no guarantee that this is true. I do not understand why the problem does not show up when the inheritance is not present. Fix:

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 + ")"
  }
}

Since Vertex and Graph will be tied to one instance of GraphKind, then T will be fixed to whatever it was defined for that instance. For example:

scala> new SimpleGraphKind[Int]
res0: SimpleGraphKind[Int] = SimpleGraphKind@1dd0fe7

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")
                ^

这篇关于在scala中混合类型参数和抽象类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆