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 不应该得到那部分吗?我只需要编译器可以知道从valto传递的值val是相同的,以便它们的内部类型必须一致。这对我来说似乎很自然,因为:

  1. val是涉及scala中不变性的最基本概念
  2. 需要路径相关的类型兼容性来对World具有完全不变性的事物进行建模(从数学角度来看这是非常需要的)
  3. 通过s的流分析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

编译器有时需要一点帮助来证明您在使用路径相关类型时所做的事情是合法的。即,正如您所说,编译器缺少流分析,因此我们必须明确告诉它我们不只是使用 any World,我们正在使用精确SomeWorld以便我们可以使用SomeWorld.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 回答