Моделирование FSM с помощью преобразователя Process1?


У меня есть машина состояний, которую я хотел бы смоделировать с помощью процесса scalaz-stream1.

Машина состояний моделирует поток сообщений между клиентом и сервером.

Базовый набор типов данных может быть следующим:

sealed trait ServerState
case object Disconnected extends ServerState
case object Authenticating extends ServerState
case object Idle extends ServerState
case object Busy extends ServerState

sealed trait Message
case object Query extends Message
case object StartupMessage extends Message
case object AuthenticationOk extends Message
case object QueryResponse extends Message

В моей голове это было бы смоделировано Process1[I, O], где type I = Message и type O = scalaz.State[Message, ServerState].

Это похоже на туман - я могу видеть контуры решения, но твердое определение его ускользает от меня.

В настоящее время у меня есть что-то похожее это

type Transition = scalaz.State[Message, ServerState]
val connecting = Transition { StartupMessage => (StartupMessage, Authenticating) }
def fsm(state: Transition): Process1[Message, Transition] = {
  Await [Message, Transition] { msg =>
    case (connecting, AuthenticationOk) => Emit1(connecting) 
  }
}
Я знаю, что это неправильно, но я не могу понять, где должны жить переходные состояния. Должен ли процесс принимать Message и возвращать физическое ServerState, в то время как драйвер Process1 обрабатывает внутреннее состояние? Я изо всех сил пытаюсь понять, как "донести" сообщение, которое не может быть выполнено в данный момент.

Пример:

1. Current ServerState = Disconnected
2. StateMachine gets Query Message
3. StateMachine must send StartupMessage, ServerState now equals = Authenticating
4. StateMachine receives AuthenticationOk, ServerState now equals Idle
5. StateMachine must now sends original query message, ServerState now equals Busy
6. StateMachine gets QueryResponse, ServerState now equals Idle
1 3

1 ответ:

Я думаю, что вы должны быть в состоянии кодировать вашу государственную машину через рекурсивный Process1[Message, Message] Вот так

def fsm(state: ServerState): Process1[Message, Message] = {
  receive1 { msg: Message =>
    (msg, state) match {
      case (Query, Disconnected) => 
        emit(StartupMessage) fby fsm(Authenticating)
       case (AuthenticationOk, Authenticating) => 
         fsm(Idle)
      ...
    }
  }
}

Возможно, вы захотите различать Messages, которые ваша машина принимает как события (для запуска переходов), и те, которые она выдает (как "действия"), имея Process1[InMessage, OutMessage]