Hatena::ブログ(Diary)

cooldaemonの備忘録 RSSフィード

2010-10-28

PartialFunction で FSM(Finite State Machine) やってみた

Twitter で FSM を Actor 無しで…みたいな話しが出ていたのでやってみました。

突っ込み添削大歓迎です。

main の中の zip が余分だった。List(FSM(GetState) -> State1, FSM(ToState2) -> State2, ...) の方が読みやすい。

object Test {
  def main (args: Array[String]) {
    List(
        FSM(GetState)
      , FSM(ToState2)
      , FSM(GetState)
      , FSM(ToState2)
      , FSM(ToState1)
      , FSM(GetState)
    ) zip List (
        State1
      , State2
      , State2
      , State2
      , State1
      , State1
    ) find {x => x._1 != x._2} match {
      case None => println("Success!")
      case _    => println("Failure!")
    }
  }
}

abstract class Event
case object ToState1 extends Event
case object ToState2 extends Event
case object GetState extends Event

abstract class State
case object State1 extends State
case object State2 extends State

object FSM {
  var state: PartialFunction[Event, State] = state1 orElse inaction

  def state1: PartialFunction[Event, State] = {
    case GetState =>
      State1
    case ToState2 =>
      state = state2 orElse inaction
      State2
  }

  def state2: PartialFunction[Event, State] = {
    case GetState =>
      State2
    case ToState1 =>
      state = state1 orElse inaction
      State1
  }

  def inaction: PartialFunction[Event, State] = {
    case _ => state(GetState)
  }

  def apply(event: Event): State = state(event)
}

以前書いた Actor 版はこちら

xuweixuwei 2010/10/30 11:04 ) find {x => x._1 != x._2} match {

のところは、findしたあとの結果を使用しないなら、findではなくforallかexistsのほうがいい気がします。無駄なListを生成しないので。

cooldaemoncooldaemon 2010/11/05 00:49 ありがとうございます。
確かに、exists で事足りるので、そちらにかえてみます。

katzchangkatzchang 2010/11/11 14:30 ようやく読めるようになってきましたw
case ToState2 =>
state = state2 orElse inaction
State2
でちょっと混乱しましたが、var state はStatusオブジェクトの管理ではなく、状態遷移の管理なわけですね。

あと、想定外の状態遷移が呼ばれた場合にはGetStateに戻してる部分、何らかの例外通知みたいな扱いができれば面白そうですね。よくわからないけど、Optionでラップするとか…。本当によくわからないけどw

はてなユーザーのみコメントできます。はてなへログインもしくは新規登録をおこなってください。

トラックバック - http://d.hatena.ne.jp/cooldaemon/20101028/1288231179