言語ゲーム

とあるエンジニアが嘘ばかり書く日記

Twitter: @propella

Reactive Programming の事をつらつら書く。

最近再び Functional Reactive Programming (FRP) について調べているのでまとまり無くメモする。まず大まかな言葉の意味については http://en.wikipedia.org/wiki/Reactive_programming から辿るのが良いと思う。簡単に言うと、FRP とはスプレッドシートの計算モデルを拡張したライブラリや言語、プログラミング技術の事を言う。Function という言葉は付いていたり付いていなかったりするけど、Reactive Programming は副作用を制限する手法なので、どの手法も多かれ少なかれ関数的に使う。

FRP はかなり大雑把に使われる言葉なので人に説明するのが難しい。だけどよく似た粒度の言葉としてはコレクションライブラリくらいが丁度良いと思う。関数プログラミングや論理プログラミングのような大げさな言葉では無い。APL や内包表現のように専用の文法が用意される事もあれば、ただのライブラリとして実装される事もある。コレクションの役割が細かい実装を隠して集合操作を書く事であるように、FRP の目的は細かい実装を隠してデータの依存関係を書く事だ。単にデータフローの今風の言い方と思ってもいい。依存関係というと Observer Pattern が思い浮かぶけど、Observer Pattern より大きな粒度だ。FRP の実装に Observer Pattern を使ってもいいし、使わなくても良い。

依存関係(依存グラフ)は無閉路有向グラフで記述される。無閉路有向グラフというのは要するに同じ所をグルグル回ることの無い関係という事だ。普通の副作用付きプログラミングでは代入によって好きな所に好きな順序でデータを入れる事が出来るが、FRP では必ずどっちが入力でどっちが出力かはっきり順序が決まっている。これが副作用を制限するという意味だ。これじゃグルグルお互いを追い掛け回すネコとかネズミとかは表現できないじゃないか!と思うかも知れないけど、過去の車と未来の車は違うものだと考える事で、だいたい解決する。これがスプレッドシートを拡張したという意味だ。スプレッドシートでは相互依存する関係を書けないが、FRP では時間さえずらせば問題ない。

FRP はだいたいデータフローなんだけど、さらに今風のボキャブラリに色々出会うことが良くある。

Lifting

Lifting というのは、普通の値の操作を 依存グラフ(スプレッドシートのセルのような物)の操作に変換する事だ。例えばスプレッドシートで A1 + A2 と書いてある時、+ の意味は普通の言語とは違う。普通の言語では両辺を足すという意味だけど、スプレッドシートでは、両辺が示すセルが更新された時に + を計算しなおしたセルという意味になる。この単純な + から拡張された + を作る事を Lifting という。特に関数型言語ではセルに限らずリスト操作や副作用操作など拡張する変換を何でも Lifting という。オブジェクト指向での似た用語は Delegation (移譲)だ。例えば Squeak の Collection >> + の実装は各要素に + を移譲した結果で新しい Collection を作る。

Behavior と Event

FRP の一部では、依存グラフを Behavior と Event の二種類に分けて考える。Behavior は時間的に連続して変化する値を表し、Event は断続的な変化を表す。どちらも変化する値なんだから同じで良いじゃないか!という気もするが、実用上これは別に考えた方が良いらしい。まだそういう状況を見たことが無いのでよく分からない。

Push と Pull と Polling

これもちゃんと定義された用法では無いと思うけど、FRP を実装する際、大まかに二つの方針がある。オブジェクトが変化した時に、そのオブジェクトに依存している先のオブジェクトをドミノ倒し的に変化させていく方式(Push)と、あるオブジェクトの状態が必要になった時、オブジェクトが依存している元のオブジェクトの状態を次々取得していく方法だ(Pull)。特に定期的に Pull するものを Polling と呼ぶ。

もしも依存グラフ内に副作用がなければ、この実装の違いに依らず同じ結果が得られるはずなので、Push と Pull の違いは最適化の違いだ。イベント更新頻度が画面更新頻度よりも多ければ Pull が軽くなり、イベント更新頻度が画面更新頻度よりも少なければ Push が軽くなる。

Higher-order reactive programming

ここから先はスプレッドシートの枠内に収まらない話。例えばドラッグアンドドロップをモデル化する事を考える。マウスが押された時、マウスが動かされた時、マウスが離された時のそれぞれの状態に対して別の依存グラフを作らないと行けない。どうするかというと、最初にマウスが押された時に、次の状態を表す依存グラフ自体を値とする依存グラフを構築する。こういう仕組みを使ってステートマシンを作る。このあたり実際自分で作ってみないと分からないなー。

FRP と人気の Excel, Scratch, Processing, Arduino について。

FRP はエンドユーザ向けプログラミング言語を拡張するための指針になるんじゃないかなと思っている。例えば Excel を拡張するには、元にシンプルなスプレッドシート言語にいきなりフル機能(かっこ良く言うとチューリング完全)の Basic マクロが追加される。そこまで一気に機能アップすると出来ることが増えるが余計なエラーも増える。そこで、FRP のようにイベントと過去の値を参照して現在の値を決めることが出来る言語だけを追加すればどうだろうか?

最近人気の Scratch, Processing, Arduino は共通の性質を持つ。それは初期値の決定とループ処理という定形が最初から組み込まれている事だ。なぜループが組み込まれているだけで親しみやすい言語になるのかは面白い問題だ。とにかく基本的にユーザはループの中にプログラムを書くので、知らずにコードは Lifting されていると考える事が出来る。この基本ループという構造は副作用さえ抜きにすれば FRP の Polling 実装と同じ物だ。という事は、ここにも FRP 的拡張がしっくり来るのでは無いかと思っている。