あの説明じゃ、状態遷移をどうやって実装するのかが全然イメージ湧かないので、そこが結構苦労した。有限状態機械ってのは、状態と操作がいくつかあって、
f(元の状態, 操作) -> ( 次の状態, イベント出力 )
という状態遷移(写像)が、すべての状態について定義できる機械のこと。なので、この写像がgen_fsmの中でどういう風に実現されているかがまずは出発点。で、gen_fsmでは
状態A(操作x、状態変数)-> イベント出力, {next_state, 状態B, 次の状態変数}; 状態A(操作y、状態変数)-> イベント出力, {next_state, 状態C, 次の状態変数}. 状態B(操作z、状態変数)-> イベント出力, {next_state, 状態A, 次の状態変数}; ....
てな感じである。操作zには、関数として定義されたものだけでなくてtimeoutなんていうものも使える。スレッドセーフで当然だし。すげーよOTP。
関係ないけど、最初はこっちのFSMのことかとおモタ。
A behaviour module for implementing a finite state machine. A generic finite state machine process (gen_fsm) implemented using this module will have a standard set of interface functions and include functionality for tracing and error reporting. It will also fit into an OTP supervision tree.
- 参考:
- コード:
- 子供サンプル。最初は泣いていて、褒めると笑う。ほっとくとまたぐずって、褒めると笑う。
- 笑ってるときにおどかすと泣く。
- ぐずっているときにもっとほっとくと、やっぱり泣き出す。
-module(test_fsm). -author('kuenishi@gmail.com'). -behaviour(gen_fsm). %%finite state machine sample %% see also: $ erl -man gen_fsm %% STATE DIAGRAM OF AN INFANT: any other state transition event is ignored. name that has ! is an event. %% %% +--------> crying <-------+ %% | | | %% | | praise! | scare! %% |timeout | | %% | (10sec) +-> happy ---+ %% | | <----+ %% | timeout| | %% | (5sec)| | praise! %% | | | %% +--------- sad <---+ | %% | | %% +-------------+ %%> test_fsm:start(). %%> test_fsm:praise(). %%> test_fsm:scare(). %%> test_fsm:stop(). -compile(export_all). %-module(code_lock). start() -> gen_fsm:start_link({local, ?MODULE}, ?MODULE, [], []). stop() -> gen_fsm:send_all_state_event(?MODULE, stop). scare() -> gen_fsm:send_event(?MODULE, scare). praise() -> gen_fsm:send_event(?MODULE, praise). init(_) -> io:format("~p.~n", [started]), {ok, crying, []}. crying(praise, History) -> NewHistory = [crying|History], io:format("~p , ~p.~n", [crying, History]), {next_state, happy, NewHistory, 5000}; crying(_, History)-> {next_state, sad, History}. happy(scare, History)-> NewHistory = [happy|History], io:format("~p , ~p.~n", [happy, History]), {next_state, crying, NewHistory}; happy(praise, History)-> NewHistory = [happy|History], io:format("~p , ~p.~n", [happy, History]), {next_state, happy, History, 5000}; happy(timeout, History)-> NewHistory = [happy|History], io:format("~p , ~p.~n", [happy, History]), {next_state, sad, NewHistory, 10000}; happy(_, History)-> {next_state, happy, History, 5000}. sad(praise, History)-> NewHistory = [sad|History], io:format("~p , ~p.~n", [sad, History]), {next_state, happy, NewHistory, 5000}; sad(timeout, History) -> NewHistory = [sad|History], io:format("~p , ~p.~n", [sad, History]), {next_state, crying, NewHistory, 10000}; sad(_, History)-> {next_state, sad, History, 10000}. handle_event(stop, _StateName, StateData) -> {stop, normal, StateData}. terminate(normal, _StateName, _StateData) -> ok.