在scala中为强类型状态机继承带有不同类型参数的特征



我试图在当前应用程序的上下文中创建一个状态机。下面是我正在尝试做的一个例子。

我已经定义了一系列状态,这些状态将随着应用程序的增长而增长,并且单个状态可以过渡到任何数量的其他特征(例如:A可以过渡到B, C或D)。我希望能够在所有状态上进行模式匹配,以便编译器警告我,如果我缺少任何。

sealed trait State {
  val name: String
}
// can transition to B or C
case class StateA(data: String) extends State{
  val name = "A"
}
// can transition to C
case class StateB(data: String) extends State with BuiltFrom[StateA]{
  val name = "B"
}
/*
 *  ISSUE: class StateC inherits different type instances of trait BuiltFrom: BuiltFrom[StateB] and BuiltFrom[StateA]
 */
case class StateC(data: String) extends State with BuiltFrom[StateA] with BuiltFrom[StateB]{
  val name = "C"
}
sealed trait BuiltFrom[-State]
// Attempted to use these
// sealed trait FromA extends BuiltFrom[StateA]
// sealed trait FromB extends BuiltFrom[StateB]

我试图用BuiltFrom特性来定义什么转换是可能的。它的目的是允许编译器阻止我定义无效的转换,并在我对转换的结果进行模式匹配以确定我们现在处于什么状态时警告我(而不是匹配所有状态,我只匹配可能状态的子集)。

abstract class Transition[S <: State, V](state: S) {
  // Abstract member to define the transition
  protected def trans(s: S, v: V): BuiltFrom[S]
  // syntactical sugar
  def transition(v: V): BuiltFrom[S] = trans(state, v)
}

上面我定义了转换,对于任何状态S,唯一可以返回的新状态必须是BuiltFrom[S]类型。我还接受进行转换所需的一些数据(通常是post表单数据)。

case class PostedFormData(data: String)
case class TransitionA(a: StateA) extends Transition[StateA, PostedFormData](a) {
  def trans(state: StateA, formData: PostedFormData) = {
    if (formData.data.length > 0 ){ // for the sake of an example condition
      StateB(formData.data)
    }
    else{
      StateC(formData.data)
    }
  }
}
object TransitionA{
  implicit def stateAToTransitionA(s: StateA): TransitionA = TransitionA(s) // implicit conversion
}

上面是一个示例过渡。我希望能够返回类型为BuiltFrom[StateA]的状态。

object Controller {
  // Example usage
  def action(state: StateA) = {
    val form_data = PostedFormData("Some Data")
    val new_state: BuiltFrom[StateA] = TransitionA.stateAToTransitionA(state).transition(form_data) // why will the implicit conversion not work here?
    // Extract the new state
    new_state match {
      case b: StateB => {"B"}
      case c: StateC => {"C"}
    }
  }

上面是我想在控制器级别使用转换代码的方式。理想情况下,隐式转换应该工作,但重要的是,我可以对返回的状态进行模式匹配,以确定我所处的新状态。

我遇到的问题是可以从多个状态过渡到的状态。我得到以下错误:

类StateC继承了特性BuiltFrom的不同类型实例:BuiltFrom[StateB]和BuiltFrom[StateA]

我想知道是否有一种方法可以解决这个问题。或者,我愿意接受重新设计的建议,以实现相同的目标(尽可能地利用编译器)。

谢谢!

我建议您不要尝试运行自己的有限状态机,而是查看一些现有的选项:

  • Akka FSM
  • FSM的Java库

最新更新