在 Scala 中构建 `this.type` 的实例
Building instances of `this.type` in Scala
我正在研究一个名为 Graphlike
的图形特征,我在其中使用 dependent/associated 类型作为顶点。在 之后,我的实现如下所示:
trait Graphlike {
type Vertex
def subgraph(selectedVertices: Set[Vertex]): this.type
}
我还有各种抽象的原子状态自动机,当然它们的行为类似于图形:
trait Automaton extends Graphlike {
type State
type Vertex = State
def states: Iterable[State]
def initialState: State
def getBuilder: AutomatonBuilder[this.type]
def subgraph(selectedVertices: Set[Vertex]) = {
val builder = getBuilder
// Some logic to actually do something to the builder here
builder.getAutomaton
}
}
trait AutomatonBuilder[A <: Automaton] {
def getAutomaton: A
}
然而,当我尝试实际实现一个具体的自动机时,我 运行 遇到了麻烦:
class ConcreteAutomaton extends Automaton {
type State = Int
def states = List(1, 2, 3)
def initialState = 1
def getBuilder = new ConcreteAutomatonBuilder
}
class ConcreteAutomatonBuilder extends AutomatonBuilder[ConcreteAutomaton] {
def getAutomaton = new ConcreteAutomaton
}
class UsesAutomataAsGraphs {
val aut = new ConcreteAutomaton
aut.subgraph(Set(aut.initialState)).subgraph(Set(aut.initialState))
}
给出:
[info] Compiling 1 Scala source to /Users/albin/Downloads/example/target/scala-2.12/classes ...
[error] /Users/albin/Downloads/example/src/main/scala/example/Example.scala:33:20: type mismatch;
[error] found : ConcreteAutomatonBuilder
[error] required: AutomatonBuilder[ConcreteAutomaton.this.type]
[error] Note: ConcreteAutomaton >: ConcreteAutomaton.this.type (and ConcreteAutomatonBuilder <: AutomatonBuilder[ConcreteAutomaton]), but trait AutomatonBuilder is invariant in type A.
[error] You may wish to define A as -A instead. (SLS 4.5)
[error] def getBuilder = new ConcreteAutomatonBuilder
[error] ^
按照建议并使 A 逆变给了我其他问题。这也不是我真正想要的;我希望我的建造者生产完全相同类型的自动机。
"Building instances of this.type
" 听起来很奇怪。不管怎样:
trait Graphlike {
type Vertex
def subgraph(selectedVertices: Set[Vertex]): this.type
}
trait Automaton extends Graphlike {
type State
type Vertex = State
def states: Iterable[State]
def initialState: State
def getBuilder: AutomatonBuilder[this.type]
def subgraph(selectedVertices: Set[Vertex]): this.type = {
val builder = getBuilder
// Some logic to actually do something to the builder here
builder.getAutomaton
}
}
trait AutomatonBuilder[A <: Automaton] {
def getAutomaton: A
}
class ConcreteAutomaton extends Automaton {
type State = Int
def states = List(1, 2, 3)
def initialState = 1
def getBuilder = new ConcreteAutomatonBuilder[this.type](this)
}
class ConcreteAutomatonBuilder[A <: Automaton with Singleton](a: A) extends AutomatonBuilder[A] {
def getAutomaton = a
}
Automaton
知道AutomatonBuilder
也很奇怪。
我在这里添加另一个答案,因为它与另一个答案明显不同,而且会变得太大。这个使用 typeclasses 和 implicit classes 来做所有事情,我觉得它更安全,尽管它可能看起来像样板,而且对你来说有点太多了。
不同的对象不是将subgraph
放在Graphlike
特征中,而是使用子图方法并构造新的自动机。隐式 class 提供了 subgraph
方法,因为我无法证明 G
是 Graphlike
特征本身中 this
的类型。
斯卡斯蒂:https://scastie.scala-lang.org/bYTXEzS3T6uNMShDIjQghA
trait Graphlike {
type Vertex
}
trait Automaton extends Graphlike {
type State
type Vertex = State
def states: Iterable[State]
def initialState: State
}
class ConcreteAutomaton extends Automaton {
type State = Int
def states = List(1, 2, 3)
def initialState = 1
}
trait AutomatonBuilder[+A <: Automaton] {
def getAutomaton: A
}
class ConcreteAutomatonBuilder extends AutomatonBuilder[ConcreteAutomaton] {
def getAutomaton = new ConcreteAutomaton
}
trait Subgraph[G <: Graphlike] {
def subgraph(graph: G)(selectedVertices: Set[graph.Vertex]): G
}
trait AutomatonSubgraph[A <: Automaton] extends Subgraph[A] {
protected def newBuilder: AutomatonBuilder[A]
def subgraph(automaton: A)(selectedVertices: Set[automaton.Vertex]): A = {
val builder = newBuilder
//Do stuff to the builder here
builder.getAutomaton
}
}
implicit object ConcreteAutomatonSubgraph extends AutomatonSubgraph[ConcreteAutomaton] {
protected def newBuilder = new ConcreteAutomatonBuilder()
}
implicit class Subgraphable[+G <: Graphlike](graph: G)(implicit sub: Subgraph[G]) {
def subgraph(selectedVertices: Set[graph.Vertex]): G = sub.subgraph(graph)(selectedVertices)
}
class UsesAutomataAsGraphs {
val aut = new ConcreteAutomaton
val x = aut.subgraph(Set(aut.initialState)).subgraph(Set(aut.initialState))
}
另一种更忠实于您的原始设计但我不喜欢的方法:https://scastie.scala-lang.org/AfKX5cpbSXqrqesT4rsUvA
按照 Dmytro Mitin 在另一个问题上的 ,您可以通过使子图接受 Set[A#Vertex]
而不是 Set[this.Vertex]
来做到这一点。您不能像我在那里的回答中建议的那样使用 this.type
,因为您从中获取子图的原始自动机可能会实现您的构建者不可能知道的各种东西。
trait Graphlike[G <: Graphlike[G]] {
type Vertex
def subgraph(selectedVertices: Set[G#Vertex]): G
}
trait Automaton[A <: Automaton[A]] extends Graphlike[A] {
type State
type Vertex = State
def getBuilder: AutomatonBuilder[A]
def states: Iterable[State]
def initialState: State
def subgraph(selectedVertices: Set[A#Vertex]): A = {
val builder = getBuilder
// Some logic to actually do something to the builder here
builder.addVertices(selectedVertices) //Example
builder.getAutomaton
}
}
trait AutomatonBuilder[A <: Automaton[A]] {
def getAutomaton: A
//example
val verts = Set[A#Vertex]()
def addVertices(s: Set[A#Vertex]): Unit = verts ++ s
}
class ConcreteAutomaton extends Automaton[ConcreteAutomaton] {
type State = Int
def states = List(1, 2, 3)
def initialState = 1
val getBuilder = new ConcreteAutomatonBuilder
}
class ConcreteAutomatonBuilder extends AutomatonBuilder[ConcreteAutomaton] {
def getAutomaton = new ConcreteAutomaton
}
class UsesAutomataAsGraphs {
val aut: ConcreteAutomaton = new ConcreteAutomaton
aut.subgraph(Set(aut.initialState)).subgraph(Set(aut.initialState))
}
我正在研究一个名为 Graphlike
的图形特征,我在其中使用 dependent/associated 类型作为顶点。在
trait Graphlike {
type Vertex
def subgraph(selectedVertices: Set[Vertex]): this.type
}
我还有各种抽象的原子状态自动机,当然它们的行为类似于图形:
trait Automaton extends Graphlike {
type State
type Vertex = State
def states: Iterable[State]
def initialState: State
def getBuilder: AutomatonBuilder[this.type]
def subgraph(selectedVertices: Set[Vertex]) = {
val builder = getBuilder
// Some logic to actually do something to the builder here
builder.getAutomaton
}
}
trait AutomatonBuilder[A <: Automaton] {
def getAutomaton: A
}
然而,当我尝试实际实现一个具体的自动机时,我 运行 遇到了麻烦:
class ConcreteAutomaton extends Automaton {
type State = Int
def states = List(1, 2, 3)
def initialState = 1
def getBuilder = new ConcreteAutomatonBuilder
}
class ConcreteAutomatonBuilder extends AutomatonBuilder[ConcreteAutomaton] {
def getAutomaton = new ConcreteAutomaton
}
class UsesAutomataAsGraphs {
val aut = new ConcreteAutomaton
aut.subgraph(Set(aut.initialState)).subgraph(Set(aut.initialState))
}
给出:
[info] Compiling 1 Scala source to /Users/albin/Downloads/example/target/scala-2.12/classes ...
[error] /Users/albin/Downloads/example/src/main/scala/example/Example.scala:33:20: type mismatch;
[error] found : ConcreteAutomatonBuilder
[error] required: AutomatonBuilder[ConcreteAutomaton.this.type]
[error] Note: ConcreteAutomaton >: ConcreteAutomaton.this.type (and ConcreteAutomatonBuilder <: AutomatonBuilder[ConcreteAutomaton]), but trait AutomatonBuilder is invariant in type A.
[error] You may wish to define A as -A instead. (SLS 4.5)
[error] def getBuilder = new ConcreteAutomatonBuilder
[error] ^
按照建议并使 A 逆变给了我其他问题。这也不是我真正想要的;我希望我的建造者生产完全相同类型的自动机。
"Building instances of this.type
" 听起来很奇怪。不管怎样:
trait Graphlike {
type Vertex
def subgraph(selectedVertices: Set[Vertex]): this.type
}
trait Automaton extends Graphlike {
type State
type Vertex = State
def states: Iterable[State]
def initialState: State
def getBuilder: AutomatonBuilder[this.type]
def subgraph(selectedVertices: Set[Vertex]): this.type = {
val builder = getBuilder
// Some logic to actually do something to the builder here
builder.getAutomaton
}
}
trait AutomatonBuilder[A <: Automaton] {
def getAutomaton: A
}
class ConcreteAutomaton extends Automaton {
type State = Int
def states = List(1, 2, 3)
def initialState = 1
def getBuilder = new ConcreteAutomatonBuilder[this.type](this)
}
class ConcreteAutomatonBuilder[A <: Automaton with Singleton](a: A) extends AutomatonBuilder[A] {
def getAutomaton = a
}
Automaton
知道AutomatonBuilder
也很奇怪。
我在这里添加另一个答案,因为它与另一个答案明显不同,而且会变得太大。这个使用 typeclasses 和 implicit classes 来做所有事情,我觉得它更安全,尽管它可能看起来像样板,而且对你来说有点太多了。
不同的对象不是将subgraph
放在Graphlike
特征中,而是使用子图方法并构造新的自动机。隐式 class 提供了 subgraph
方法,因为我无法证明 G
是 Graphlike
特征本身中 this
的类型。
斯卡斯蒂:https://scastie.scala-lang.org/bYTXEzS3T6uNMShDIjQghA
trait Graphlike {
type Vertex
}
trait Automaton extends Graphlike {
type State
type Vertex = State
def states: Iterable[State]
def initialState: State
}
class ConcreteAutomaton extends Automaton {
type State = Int
def states = List(1, 2, 3)
def initialState = 1
}
trait AutomatonBuilder[+A <: Automaton] {
def getAutomaton: A
}
class ConcreteAutomatonBuilder extends AutomatonBuilder[ConcreteAutomaton] {
def getAutomaton = new ConcreteAutomaton
}
trait Subgraph[G <: Graphlike] {
def subgraph(graph: G)(selectedVertices: Set[graph.Vertex]): G
}
trait AutomatonSubgraph[A <: Automaton] extends Subgraph[A] {
protected def newBuilder: AutomatonBuilder[A]
def subgraph(automaton: A)(selectedVertices: Set[automaton.Vertex]): A = {
val builder = newBuilder
//Do stuff to the builder here
builder.getAutomaton
}
}
implicit object ConcreteAutomatonSubgraph extends AutomatonSubgraph[ConcreteAutomaton] {
protected def newBuilder = new ConcreteAutomatonBuilder()
}
implicit class Subgraphable[+G <: Graphlike](graph: G)(implicit sub: Subgraph[G]) {
def subgraph(selectedVertices: Set[graph.Vertex]): G = sub.subgraph(graph)(selectedVertices)
}
class UsesAutomataAsGraphs {
val aut = new ConcreteAutomaton
val x = aut.subgraph(Set(aut.initialState)).subgraph(Set(aut.initialState))
}
另一种更忠实于您的原始设计但我不喜欢的方法:https://scastie.scala-lang.org/AfKX5cpbSXqrqesT4rsUvA
按照 Dmytro Mitin 在另一个问题上的 Set[A#Vertex]
而不是 Set[this.Vertex]
来做到这一点。您不能像我在那里的回答中建议的那样使用 this.type
,因为您从中获取子图的原始自动机可能会实现您的构建者不可能知道的各种东西。
trait Graphlike[G <: Graphlike[G]] {
type Vertex
def subgraph(selectedVertices: Set[G#Vertex]): G
}
trait Automaton[A <: Automaton[A]] extends Graphlike[A] {
type State
type Vertex = State
def getBuilder: AutomatonBuilder[A]
def states: Iterable[State]
def initialState: State
def subgraph(selectedVertices: Set[A#Vertex]): A = {
val builder = getBuilder
// Some logic to actually do something to the builder here
builder.addVertices(selectedVertices) //Example
builder.getAutomaton
}
}
trait AutomatonBuilder[A <: Automaton[A]] {
def getAutomaton: A
//example
val verts = Set[A#Vertex]()
def addVertices(s: Set[A#Vertex]): Unit = verts ++ s
}
class ConcreteAutomaton extends Automaton[ConcreteAutomaton] {
type State = Int
def states = List(1, 2, 3)
def initialState = 1
val getBuilder = new ConcreteAutomatonBuilder
}
class ConcreteAutomatonBuilder extends AutomatonBuilder[ConcreteAutomaton] {
def getAutomaton = new ConcreteAutomaton
}
class UsesAutomataAsGraphs {
val aut: ConcreteAutomaton = new ConcreteAutomaton
aut.subgraph(Set(aut.initialState)).subgraph(Set(aut.initialState))
}