您的转换仅适用于某种类型的状态,但也适用于某种类型的状态机,因此两种类型参数 S 和 M . 例如,最后,您的转换可能取决于温度,这是StateMachine的属性,而不仅仅是State .

不知何故,状态机应该只有与之兼容的转换 . 在没有温度的状态机上,不允许需要访问温度的转换 . 类型系统将强制执行该操作 . 但是,您的代码没有为此做出任何规定 .

相反,你有一个StateMachine类得到一个转换集[S,StateMachine [S]] . 这是有效的,但结果是StateMachine只接受“标准”转换,不需要机器上的任何特殊转换 . 您可以定义需要特殊机器(带温度)的转换,但即使机器与它兼容,机器也无法接受这些特殊转换 .

然后是你的Hvac机器,它有温度 . 你试图给它传递特殊的过渡,只能在Hvac机器上运行的过渡(访问温度) . 但是祖先构造函数被编写为仅接受标准转换 . 编译器拒绝这一点 . 它表明,如果过渡在M中是协变的,那就没问题 . 这是真的,除了过渡在M中不能协变 . 它需要一台机器作为输入 . 协变过渡意味着如果它可以在非常特殊的机器上运行,它也必须能够在不太特殊的机器上运行 . 不是你想要的 .

您需要做的是让StandardMachine类接受特殊的转换,它现在拒绝,但当然只有与机器兼容的转换(如果您不提供此保证,编译器将拒绝代码) . 可能更简单的方法是将类型M放在机器中,以便您可以正确地表达约束 .

这是一种可行的方法 . 首先,我们向StateMachine添加一个类型参数

class StateMachine[S, M](

我们需要在引用StateMachine的地方添加M参数,例如 class Transition[S, M <: statemachine m class hvac extends>

当然,构造函数参数变为

class StateMachine[S,M](transitions: Set[Transition[S, M]]], ...

在这里,我们声明机器可以进行过渡 . 除了我们没有 . 它仍然无法编译,每次我们将 this ,机器传递给转换,例如:

transitionsOut.filter(_.willFollow(this, true)).foreach {transition =>

^^

type mismatch; found : StateMachine.this.type (with underlying type StateMachine[S,M]) required: M

好吧,我们介绍了M型,但我们没有将一些M传递给机器,我们正在通过 this . 这是一个StateMachine [S,M],它不需要是M.我们当然希望M成为机器的类型,但不一定是这种情况 . 我们不愿意声明StateMachine [S,M]必须是M.我们用自我类型来做:

class StateMachine[S, M](
transitions: Set[Transition[S, M]],
initialStates: Set[S]) { this: M =>
// body of the class
}

this:M =>声明类的每个实例都必须是泛型参数M的实例 . 我们强制它为M,因此错误消失 .

那么 Transition 中的约束 M <: statemachine m transition .>

这充分利用了类型系统的问题,但是它可能更容易隔离机器状态,也就是说,而不是让自己 def machineState: M ,而不是 def machineState: M ,并将其传递给警卫而不是 this . 在这种情况下, Hvac 将是 StateMachine[HvacState, Double] (或者更温和的封装温度比Double),

我的更改摘要:

转换:删除M上的约束,删除协方差:

class Transition [S,M](...

EpsilonTransition:删除对M的约束

class EpsilonTransition [S,M]

StateMachine :添加类型参数 M ,使用 M 作为转换参数,并将 M 设置为自身类型:

class StateMachine [S,M](过渡:设置[Transition [S,M]],initialStates:Set [S]){this:M =>

turnOffAcc :您复制的代码中缺少运算符,添加 <

HVac :将自身添加为第二个通用参数: class HVac extends StateMachine[HvacState] . 此外,某些转换, AcToHeater 和 HeaterToAc 不会出现在您复制的代码中,所以我只是将它们删除了 .