Общая конечная машина (преобразователь) в Scala

Каков общий способ реализации конечного автомата (или преобразователя конечного состояния) в Scala?

Я часто нуждаюсь в реализации государственного аппарата. Моя типичная реализация выглядит как

object TypicalFSM { // actually — finite state transducer
  type State
  case object State1 extends State
  case object State2 extends State
  type Message
  case object Message1 extends Message
  type ResultMessage
  case object ResultMessage1 extends ResultMessage
}

import TypicalFSM._

class TypicalFSM extends ((Message) =>Seq[ResultMessage]){
  var state:State = State1

  def apply(message:Message):Seq[ResultMessage] = (state, message) match {
    case (State1, Message1) =>
      state = State2
      Seq(ResultMessage1, ResultMessage2)
  }
}

То, что мне не нравится, - это изменяемый var, который делает поток решений небезопасным. Также топология FSM не ясна.

  • Как создать FSM в функциональном режиме?

  • Также было бы неплохо нарисовать FSM-граф в . dot format

  • Akka FSM обладает хорошим свойством разрешать ассоциировать некоторые данные с состоянием, не только указывая имя объекта. Это также приветствуется. (Тем не менее, Akka FSM не всегда удобно использовать, поскольку он асинхронный и иногда немного тяжелый.)

Ответ 1

Это, вероятно, не то, что вы ищете, но я думаю, что это интересная концепция.

object TypicalFSM {

  sealed trait State
  final class State1 extends State
  final class State2 extends State

  sealed trait Message
  case class Message1(s: String) extends Message
  case class Message2(s: String) extends Message

  sealed trait ResultMessage
  object ResultMessage1 extends ResultMessage
  object ResultMessage2 extends ResultMessage
}

import TypicalFSM._

case class Transformation[M <: Message, From <: State, To <: State](
    f:M => Seq[ResultMessage]) {

  def apply(m:M) = f(m)
}

object Transformation {

  implicit def `message1 in state1` =
    Transformation[Message1, State1, State2] { m =>
      Seq(ResultMessage1, ResultMessage2)
    }

  implicit def `message1 in state2` =
    Transformation[Message1, State2, State2] { m =>
      Seq(ResultMessage1)
    }

  implicit def `message2 in state2` =
    Transformation[Message2, State2, State1] { m =>
      Seq(ResultMessage2)
    }
}

class TypicalFSM[CurrentState <: State] {

  def apply[M <: Message, NewState <: State](message: M)(
    implicit transformWith: Transformation[M, CurrentState, NewState]) = {

    this.asInstanceOf[TypicalFSM[NewState]] -> transformWith(message)
  }
}

Использование будет таким:

def test() = {
  val s1 = new TypicalFSM[State1]
  // type of s1: TypicalFSM[State1]

  val (s2, r1) = s1(Message1("m1"))
  // type of s2: TypicalFSM[State2]

  val (s3, r2) = s2(Message1("m1"))
  // type of s2: TypicalFSM[State2]

  val (s4, r3) = s2(Message2("m2"))
  // type of s2: TypicalFSM[State1]

  // val (s5, r4) = s4(Message2("m2"))
  // Fails with:
  // 'No transformation available for TypicalFSM.Message2 in TypicalFSM.State1'
  // type of s5: TypicalFSM[State1]
}

Ваш прецедент решительно определит структуру кода в этом понятии. Вариант использования действительно определяет, какую информацию типа вы хотите сохранить.

Я понимаю это потому, что состояние сохраняется с использованием системы типов и что во время компиляции сообщается о незаконных переходах.