taiyoh's memorandum

@ttaiyoh が、技術ネタで気づいたことを書き溜めておきます。

有限オートマトンの習作として

PerlFSM::Simpleというモジュールを書いてみた。

#!perl -w
use strict;
use warnings;
use FSM::Simple;

my $count = 0;

my $fsm = FSM::Simple->new({
    rules => {
        init => sub {
            my $state = shift;
            if ($count < 20) {
                $state->next('add');
            }
            else {
                $state->next('end');
            }
        },
        add => sub {
            ++$count;
            shift->next('init');
        }
    }
});

$fsm->register(end => sub { $count *= 5; });

$fsm->run;

print "${count}\n"; # => 100

Perl Automata
ここを参考にしながら書きました。
ソースはこっちにあります。
taiyoh/p5-FSM-Simple · GitHub

(追記:9/3)
同僚からtransaction guardはちゃんと実装した方がいいと言われたので、
インターフェイスを大幅変更。
contextオブジェクトを内部で持つようにして、それで値を取り回すように。
あとはon_entry/on_exit/on_transactionも入れた。
stateのコードとtransaction guardを分けてみたらFSA::Rulesに近くなった。

use FSM::Simple;

my $fsm = FSM::Simple->new({
    on_enter      => sub {
        my $context = shift;
        $context->{count} = 0;
        $context->{str}   = "foo";
    },
    on_transition => sub { shift->{str} .= "bar" },
    on_exit       => sub { shift->{str} .= "baz" }
});

$fsm->register(init => sub {}, [
    add => sub { shift->{count} < 20 },
    end => sub { shift->{count} >= 20 }
]);

$fsm->register(add => sub { ++shift->{count} }, [
    init => 1
]);

$fsm->register(end => sub { shift->{count} *= 5 });

$fsm->run;

print $fsm->context->{count}, # => 100