読者です 読者をやめる 読者になる 読者になる

bitterharvest’s diary

A Bitter Harvestは小説の題名。作者は豪州のPeter Yeldham。苦闘の末に勝ちえた偏見からの解放は命との引換になったという悲しい物語

ゲームの中で信号関数を自在に扱う:信号関数の定義

1.基本的な信号関数

恒等関数:ある信号aをそれ自身(信号)aへ写像する信号関数である。

identity :: SF a a

定数:ある信号bを入力し、それを出力とする信号関数を出力する。

constant :: b -> SF a b

iPre:ある信号aを入力し、それを入出力とする信号関数を出力する。

iPre :: a -> SF a a

積分:ある信号(ベクトル空間)aと別の信号sに対して、aを入出力とする信号関数である。これは、信号aを入力し、それを積分した信号aを出力する信号関数を与える。

integral :: VectorSpace a s => SF a a

これは、数式で表すと\(y(t) = \int_0^t x ( t ) dt\)である。これは、\(x (t )\)がSF a aの最初のaで、\(y ( t)\)が、SF a aの最後のaである。また、sは\(t\)である。
なお、上記の基本的な信号関数はすべて「状態を有しない」信号関数である。

2.信号関数の合成

信号関数は、信号関数同士組み合わせることができる。その中で、最も単純な結合は下図の直列結合である。
f:id:bitterharvest:20141025214233p:plain
直列結合は次のように表現される。

(>>>) :: SF a b -> SF b c -> SF a c

結合では、信号関数が主であり、信号は二の次であることに注意してほしい。(これがYampaの特徴である。)

合成を用いると次のような便利なことがある。
時間は下図のように定義できる。
f:id:bitterharvest:20141025225403p:plain
即ち、信号関数constant 1.0 と信号関数integralの直列結合で、Timeを表現できる。

time :: SF a Time
time = constant 1.0 >>> integral 

即ち、\(t = \int_0^t 1.0 dt\)である。
Yampaには大域的な時間はなく、全て、信号関数が始まった時からの局所的な時間しかない。

3.複雑な結合

下図のように信号関数が結合された例を考えることにする。
f:id:bitterharvest:20141025214902p:plain
信号関数の結合を考えるとき、直列結合の他にいくつかの結合を必要とするが、それを助けるのが、アロー記法である。arrは下図のようになっている。
f:id:bitterharvest:20141025215650p:plain
arr fはaを入力としbを出力とする関数からaを入力としbを出力とする信号関数を作り出す。

arr :: (a -> b) -> SF a b

firstは下図のようになっている。
f:id:bitterharvest:20141025215736p:plain
firstは、最初の信号関数SF a bと信号cを一緒にした信号関数SF (a c) (b c)を作り出す。

first :: SF a b -> SF (a c) (b c)

loopは下図のようになっている。
f:id:bitterharvest:20141025215805p:plain
loopは、信号がループしている信号関数を定義する。Firstとは逆の関係にある。

loop :: SF (a c) (b c) -> SF a b

3.アロー記法の応用

アロー記法を利用した例をいくつか示す。

恒等な信号関数identityは、恒等関数idを信号関数化することで得られる。

identity :: SF a a
identity = arr id

定数の信号関数constantは定数のconstを信号化することで得られる。

constant :: b -> SF a a
constant  b = arr (const b)

bを受けてcを出力する関数fと、入力aと出力bで定義されている信号関数sfを入力と、信号関数SF a cを出力する結合を^>>と定義する。これはsfとarr fを職列結合したものと同じである。

^<< :: (b -> c) -> SF a b -> SF a c
f ^<< sf = sf >>> arr f

これまでの結合を応用すると色々な結合を定義することができる。まず、並列な信号関数を表す***は
f:id:bitterharvest:20141025220056p:plain
また、二つの信号関数への分離を表す&&&は
f:id:bitterharvest:20141025220305p:plain
これらの型シグネチャは次のようになる。

(***) :: SF a b -> SF c d -> SF (a,c) (b,d)
(&&&) :: SF a b -> SF a c -> SF a (b c)

4.システムをアロー記法で表現する

アロー記法を用いると、信号関数によって複雑に結合されているシステムを信号関数のネットワークとして表現することができる。例えば、先に示したシステムは、下図のように表すことができる。
f:id:bitterharvest:20141025220628p:plain

これをHaskellで表すと次のようになる。

loop (arr (\ (x, y) -> ((x,y),x))) 
>>> (first f
     >>> (arr (\(x,y) -> (x,xy))) >>> (g ***h))))

となる。