4

私はこのトピックに関していくつか質問をしましたが、Scalaにはいくつかの非常に重要なブロックが欠けているように思われるので、今回はもっと一般的な議論にしたいと思います。

次のコード(私の実際のプロジェクトから簡略化されています)を考えてみましょう。

trait World {
  type State <: StateIntf
  def evolve(s: State): State
  def initialState: State
}

class Algorithm(world: World) {
  def process(s: world.State) {
    val s1 = world.evolve(s)
    // ... do something with s and s1
  }
}

すべてがとても美しく数学的に見えますが、

object SomeWorld extends World {...}
new Algorithm(SomeWorld).process(SomeWorld.initialState)  // incompatible type

確かにあなたは次の方法で行うことができます

trait World {
  type State <: StateIntf
  var s: State
  def evolve: Unit      // s = next state
  def initialize: Unit  // s = initial state
  def getState: StateIntf = s
}

しかし、私たちは変更可能な世界に戻ったばかりです。

これは、Scalaにフロー分析がないためだと言われています。それが問題であるなら、Scalaはその部分を手に入れるべきではありませんか?valから渡される値が同じであることをコンパイラーが認識できることだけが必要なvalので、それらの内部タイプは一致する必要があります。これは私にはとても自然に思えます:

  1. valScalaの不変性を含む最も基本的な概念です
  2. World完全な不変性(数学的な観点から非常に望ましい)などをモデル化するには、パスに依存する型の互換性が必要です。
  3. 通過のフロー分析はval問題を解決します

私はあまりにも多くを求めていますか?それとも、それを解決するための良い方法はすでにありますか?

4

2 に答える 2

6

ジェネリックスはこの問題に対するより簡単な解決策を提供すると思います:

trait World[S <: StateInf] {
  def evolve(s: S): S
  def initialState: S
}

class Algorithm[S <: StateInf](world: World[S]) {
  def process(s: S) {
    val s1 = world.evolve(s)
    // ... do something with s and s1
  }
}
于 2013-01-27T09:00:46.007 に答える
5

コンパイラーは、パス依存型を使用するときに実行していることが合法であることを証明するために、少しの助けが必要な場合があります。つまり、あなたが言ったように、コンパイラにはフロー分析がないので、単に何も使用していないことを明示的に伝える必要があります。使用できるようにWorld正確に使用しています。SomeWorldSomeWorld.initialState

あなたの場合、あなたがAlgorithmそのように変更した場合:

class Algorithm[W <: World](world: W) {
  def process(s: world.State) {
    val s1 = world.evolve(s)
    // ... do something with s and s1
  }
}

次に、以下をコンパイルします。

object SomeWorld extends World {...}
new Algorithm[SomeWorld.type](SomeWorld).process(SomeWorld.initialState)
于 2013-01-28T02:33:43.833 に答える