Kan*_*ane 4 scala path-dependent-type
我已经围绕这个主题提出了几个问题,但这次我想进行更一般的讨论,因为在我看来,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
}
}
Run Code Online (Sandbox Code Playgroud)
一切看起来都很美丽和数学,但是
object SomeWorld extends World {...}
new Algorithm(SomeWorld).process(SomeWorld.initialState) // incompatible type
Run Code Online (Sandbox Code Playgroud)
当然你可以用以下方式做
trait World {
type State <: StateIntf
var s: State
def evolve: Unit // s = next state
def initialize: Unit // s = initial state
def getState: StateIntf = s
}
Run Code Online (Sandbox Code Playgroud)
但我们只是回到可变世界.
我被告知这是因为Scala没有流量分析.如果这是问题,Scala不应该得到那块吗?我只需要一个compilor可以知道,从传递的值val来val都是一样的,所以,他们的内心类型必须一致.这对我来说似乎很自然,如:
val 是最基本的概念,涉及scala中的不变性World完全不变性之类的东西(从数学角度来看这是非常需要的)vals的流量分析解决问题我要求太多了吗?或者已经有一个很好的方法来解决它?
我认为泛型为这个问题提供了一个更简单的解决方案:
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
}
}
Run Code Online (Sandbox Code Playgroud)
在使用路径依赖类型时,编译器有时需要一些帮助来证明您正在做的事情是合法的.即,正如您所说,编译器缺少流分析,因此我们必须明确告诉它我们不仅仅使用任何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
}
}
Run Code Online (Sandbox Code Playgroud)
然后以下编译:
object SomeWorld extends World {...}
new Algorithm[SomeWorld.type](SomeWorld).process(SomeWorld.initialState)
Run Code Online (Sandbox Code Playgroud)