15

私はC++とJavaでステートマシンを作成しましたが、Ocamlのような関数型言語では作成していません。

問題は、オブジェクト言語バージョンのコードを適応させることができるかどうかわからないことです。Ocamlではレコードとバリアントがクラスよりも強力だからです。

したがって、簡単に構成できるイベント駆動有限状態マシン(UMLのような階層型)が必要です。

現場で経験を積んだ誰かがその簡単なサンプルを投稿できますか?最も一般的なトラップを回避するためだけに

ありがとう :)

編集16/03:可変状態なしでそれを行うことは可能ですか?そして、「FSM」という名前で適切にカプセル化したいのですが、モジュールまたはクラスを選択する必要がありますか?

4

4 に答える 4

12

これは、FSMをどのように操作する必要があるかによって異なります。たとえば、FSMの状態を保存して後で続行できるようにする必要がある場合、またはFSMをすぐに実行する必要がある場合などです。後者の場合、末尾再帰関数の束としてそれを行うのは簡単です。

たとえば、正規表現を想定しC((A|B)*CD)*ます。次の相互再帰関数は、この正規表現に一致するリストを認識するそれぞれのFSMの直接実装です(間違いをしなかった場合:)):

type alphabet = A | B | C | D

let rec s1 = function
  | C :: rest -> s2 rest
  | _ -> false

and s2 = function
  | [] -> true
  | (A | B) :: rest -> s2 rest
  | C :: rest -> s3 rest
  | _ -> false

and s3 = function
  | D :: rest -> s2 rest
  | _ -> false

すべての関数は、オートマトンの1つの状態に正確に対応し、その遷移関数を実装します。適用するs1 : alphabet list -> boolと、引数に対してFSMが実行されます。

PS:これが末尾呼び出しの最適化の利点と優雅さを示すアプリケーションであることに注意してください...

于 2012-02-24T19:19:30.143 に答える
9

通常、オートマトンの状態に対応するレコードを作成し、別の状態への遷移をトリガーするイベントに別のタイプがあります。状態レコードには、イベントごとに新しい状態を見つけるためのマップがあります。

遷移が文字列によってトリガーされると仮定しましょう。

type event = string

module EventMap = Map.Make(struct
    type t = event
    let compare = compare
  end)

type state = {
  state_info : ...; (* the content of that state, id, comment, etc. *)
  mutable state_transitions : state EventMap.t;
}

let next_state current_state event =
  try
    EventMap.find event current_state.state_transitions
  with Not_found -> current_state

ここでは、不明なイベントは同じ状態のままであると想定しましたが、レコードにエラー状態が含まれている可能性があります...

于 2012-02-24T17:00:28.837 に答える
8

ここに有限状態マシンを表現する際のOCamlの表現力と優雅さを示す優れた答えがあります:

ocamlのオートマトン

より深刻な使用法については、ここでfsmライブラリのような有限状態マシンライブラリを調べてみることができます。

于 2012-02-24T16:27:50.387 に答える
7

私は最近、OCamlでFSMモジュールを作成しました。これはここにあります

私のFSM実装にはいくつかの特別な要件があり、ここで指摘されている他のいくつかの要件ほど見栄えが良くない可能性がありますが、FSM自体を宣言する方法は一種の素晴らしい宣言型だと思います。特別な要件は、OCamlバージョンでFSMの動作をシミュレートできることに加えて、FSMの宣言型記述からHDL(ハードウェア記述言語)でコードを生成できる必要があることです。このため、遷移関数の代わりに述語式を使用する必要がありました(そうでない場合、関数を文字列に変換するにはどうすればよいですか?)そこで、主にFSMモジュールとcreate関数およびeval_fsm関数に焦点当てます

使用例は次のとおりです。

(*********************************************************
 * FSM testing *******************************************
*)

(* inputs to the FSM *)
let full         = Var({name ="full"; value  = F});;
let ten_minutes  = Var({name = "ten_minutes"; value = F});;
let empty        = Var({name = "empty"; value = F});;
let five_minutes = Var({name = "five_minutes"; value =F});;


(* T is true,    F is false *)
let _ = 
  assign full         F ;
  assign ten_minutes  F ;
  assign empty        F ;
  assign five_minutes F ;;

(* outputs from the FSM *)
let water_on     = Var({name = "water_on";    value = F});;
let agitate      = Var({name = "agitate";     value = F});;
let drain        = Var({name = "drain"  ;     value = F});;
let start_timer  = Var({name = "start_timer"; value = F});;
let motor_on     = Var({name = "motor_on";    value = F});;
let washed       = Var({name = "washed";    value = F});;
let soap         = Var({name = "soap";        value = F});;

let reset_actions = 
  assign water_on      F;
  assign agitate       F;
  assign drain         F;
  assign start_timer   F;
  assign motor_on      F;;

module WashStates = 
  struct
   type t =  START | FILL | WASH | DRAIN |  RINSE | SPIN | STOP
     deriving(Show, Enum)    
   let start_state = START
  end 

module LogicExp = 
  struct
    type t     = boolean Logic.bexp
    type var_t = boolean Logic.variable
    let eval_exp exp = to_bool (Logic.eval exp)
    let var_to_s     = var_to_s
  end

module WashFSM = FSM(WashStates)(LogicExp) 

open WashStates

(* declare the state table *)
(*   CS,   PREDICATE,               NS,    ACTIONs *)
let my_fsm = [
  (START, Const(T),                 FILL, [(water_on,   T); 
                                           (soap,       T)]);
  (FILL,  Bop(And,full,soap),       WASH, [(water_on,   F);
                                           (agitate,    T);
                                           (washed,     T);
                                           (start_timer,T)]);
  (WASH,  ten_minutes,              DRAIN,[(agitate,    F);
                                           (start_timer,F); 
                                           (empty,      T)]); 
  (DRAIN, Bop(And,empty,soap),      FILL, [(drain,      F); 
                                           (soap,       F);
                                           (water_on,   T)] );
  (FILL,  Bop(And,full,Not(soap)),  RINSE,[(water_on,   F); 
                                           (soap,       F);
                                           (empty,      F);
                                           (agitate,    T)]);
  (RINSE, ten_minutes,              DRAIN, [(agitate,   F);
                                            (empty,     T)] );
  (DRAIN, Bop(And,empty,Not(soap)), SPIN,  [(motor_on,  T);
                                            (start_timer,T)]);
  (SPIN,  five_minutes,             STOP,  [(water_on,  F);
                                            (drain,     F);
                                            (start_timer,F);
                                            (motor_on,  F)]);
  (STOP,  Const(T),                 STOP,  [(motor_on,  F)]);
];; 


let st_table, current_state = WashFSM.create my_fsm in

let _ = assign full T in
let current_state = WashFSM.eval_fsm st_table current_state  in
let _ = assign ten_minutes T in
let current_state = WashFSM.eval_fsm st_table current_state  in
let current_state = WashFSM.eval_fsm st_table current_state  in
let _ = (assign ten_minutes F);(assign empty T) in
let current_state = WashFSM.eval_fsm st_table current_state  in

let _ = assign five_minutes T in
let current_state = WashFSM.eval_fsm st_table current_state  in
let _ = assign five_minutes F in
let _ = assign ten_minutes T in
let current_state = WashFSM.eval_fsm st_table current_state  in
let current_state = WashFSM.eval_fsm st_table current_state  in
let _ = assign five_minutes T in
let _ = WashFSM.eval_fsm st_table current_state  in
(*...and so on...*)

(「;;」の末尾を失礼します-このコードを切り取ってREPLに貼り付けられるようにしたかったのです)

ここで使用されているコードの一部は、私のgithubのLogicプロジェクトにあります(fsm.mlはそのプロジェクトの一部です)。述語式は、TまたはF(trueまたはfalse)のいずれかに評価されます。trueの場合、現在の状態から次の状態に遷移します。 Const Tは、常に遷移を意味します。次のような式:

Bop(And, full, soap) 

fullsoapの両方がT(true)の場合、式はtrueと評価されることを意味します。

于 2012-02-24T17:22:42.640 に答える