簡體   English   中英

在 Scala 中構建 `this.type` 的實例

[英]Building instances of `this.type` in Scala

我正在研究一個名為Graphlike的圖形特征,其中我對頂點使用依賴/關聯類型。 解決了我的多態性問題后,我的實現如下所示:

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 逆變器會給我帶來其他問題。 這也不是我真正想要的。 希望我的建造者能夠生產出完全相同類型的自動機。

“構建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也很奇怪。

我在這里添加另一個答案,因為它與另一個答案明顯不同,而且它會變得太大。 這個使用類型類和隱式類來做所有事情,我覺得它更安全,即使它看起來像樣板,對你來說有點太多了。

不同的對象沒有將Graphlike subgraph中,而是執行 subgraph 方法並構造新的自動機。 隱式 class 提供了subgraph方法,因為我無法證明GGraphlike特征本身的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))
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM