State パターンっていうの?ああいうやつ?
2ch にこんなんあったよ。
オブジェクトを使わずにステートマシンを作るのによい方法はありますか?
勉強のためにStateパターンをモジュールを使ってやってみようと思ったのですが、
相互依存を回避するうまい方法が思いつきません。
また、状態をそれぞれ別モジュールにするにせよ、一箇所にまとめるにせよ、動的に切り替えるためには
結局パターンマッチさせてそれらを呼び出すようになると思いますが、もっとスマートな方法はありますか?
私はデザインパターン何それ美味しいのという人なので、まずよく判りませんでした。
流れ:
キャラクタがバイトをして財布がいっぱいになったら銀行へ行く
ということを目標金額まで繰り返し、到達したらその金がなくなるまで
家でごろ寝し、なくなったらまた働くキャラクタは
・バイトをする : 手持ちが1増える
・銀行で貯金をする : 手持ちを0にし、貯金が1増える
・家で寝る : 貯金が1減る
の状態を取ります。
財布の許容量は3、目標貯金額は5とします。
ああそうですか。で、パターンマッチいやなの。じゃあこんなのどうですか:
module Human = struct type t = { pocket : int; bank : int; } let zero = { pocket = 0; bank = 0 } end open Human module Action = struct let work h = prerr_endline "worked"; let pocket = h.pocket + 1 in assert (pocket <= 3); { h with pocket = pocket } let deposit h = prerr_endline "deposited"; { pocket = 0; bank = h.bank + 1 } let sleep h = prerr_endline "slept"; let bank = h.bank - 1 in assert (bank >= 0); { h with bank = bank } end type t = { human : Human.t; think : Human.t -> t; } module type Strategy = sig val init : t end module Bitekun : Strategy = struct let rec work h = let h = Action.work h in { human = h; think = if h.pocket >= 3 then deposite else work } and deposite h = let h = Action.deposit h in { human = h; think = if h.bank >= 5 then sleep else work } and sleep h = let h = Action.sleep h in { human = h; think = if h.bank = 0 then work else sleep } let init = { human = Human.zero; think = work } end module Workerhoric : Strategy = struct let rec work h = let h = Action.work h in { human = h; think = if h.pocket >= 3 then deposite else work } and deposite h = { human = h; think = work } let init = { human = Human.zero; think = work } end module Neet : Strategy = struct let rec sleep h = let h = Action.sleep in { human = h; think = sleep } let init = { human = Human.zero; think = sleep } end let think : t -> t = fun t -> t.think t.human let _ = let rec loop t = loop (think t) in loop Bitekun.init
まあ、状態を variant じゃないて closure にしただけだけど、ありがちなパタンマッチは無くなりました。ただこれだと各状態遷移表が mutual recursive functions で表されるから、そこを別モジュールに切っていくって訳にはいかないね。Functor で parametrize して最後に recursive module で合体させればいいか。