9.抑制(Inhibition)
Netwireを特徴づけている機能の一つは、inhibitionである。この単語のhibitの部分は、ラテン語のhabitで「つかんだり持ち続けたりすること」を表している。接頭語のinは「中に」を表す。例えば、心理学では「ある心理的機能が他の心理的機能を妨げること」を表す時に用いる。
inhibitionは、「抑制、制止、防止作用、抑止、阻害、阻害性、抑圧、妨害作用、意志制止、阻止、抑制作用」などと訳される。この記事では、inhibitionを抑制と訳して話を進めることにする。
これまで振舞いを論じてきたが、それは、正常に振る舞っているとの仮定に基づいていた。しかし、もし生き物の振舞いを扱っている場合には、例えとしては刺激的すぎるのだが、死んでしまった場合には生きていた時のような振る舞いを期待することができない。また、落下する石を考えたとき、何回か飛び跳ねたのち、石は動きを停止する。
もっと重要な事象は、連続系と離散系の違いである。連続系のシステムはどのような時間においても振舞いが定義されるが、離散系のシステムの場合には、離散的な時間(サンプリング時間)でしか振舞いは定義されない。あるサンプリング時間から次のサンプリング時間までの間の振舞いは定義されていない。しかし、連続的、離散的であるにかかわらず、振舞いが定義できるようになると、使い勝手がとてもよくなる。
上記の要望をかなえたのが抑制である。抑制はMaybeを用いて考えると分かりやすい。振舞いが定義されているときは値を返すが、そうでないときは値を返さないようにすると、Behaviorは次のように再定義できる。
newtype Behavior t a b = Behavior { stepBehavior :: t -> a -> Maybe (b,Behavior t a b) }
例えが悪かった死んだ例の場合は次のようになる。
dead :: Behavior t a b dead = Behavior $ \_ _ -> Nothing
ゲームを作成するときはこの概念は有用である。もし、抑制がない場合にはスレッドをどうこうするという全く関係のないところに話を持っていかざるを得なくなる。抑制があるおかげで、死んだままでずっとゾンビのように存在し続ける。
一度だけある動作xをしてその後は死んでしまう場合は次のように表すことができる。
dead :: Behavior t a b dead = Behavior $ \_ _ -> Nothing
ゾンビが生き返る場合は次のようになる。次のプログラムは、二つの振舞いxとyを入力し、前者xが抑制されたら後者yを実行する。
revive :: Behavior t a b -> Behavior t a b -> Behavior t a b revive x y = Behavior $ \t a -> case stepBehavior x t a of Just (xr,xn) -> return (xr,revive xn y) Nothing -> stepBehavior y t a
上記のプログラムで(xr,xn)はstepBehaviorの出力で、出力がある場合にはJustの方を、そうでない場合にはNothingの方を実行する。Justの方は、出力された振舞いxnに対してreviveを再帰的に実行する。Nothingの時は、振舞いyに移る。
reviveは次のように書き直すと、意味していることが記号からくみ取れるようになる。
(~>) :: Behavior t a b -> Behavior t a b -> Behavior t a b (~>) = revive
今日の記事はここで終わりだが、これで、やっと、実際のNetwireの説明に移ることができる。今までの記事から読み取れるように、Netwireは確固とした数学を基礎にして、組み立てられていることに特徴がある。