言語ゲーム

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

Twitter: @propella

Haskell におけるストリームとアニメーションの時刻で色々考え。

The Haskell School of Expression の15章「ストリーム」で詰まっている。ここが終わらないと次の山場の「反応アニメーション」に進めない。難しいところは、クライアントサーバを再帰関数でシミュレートする所。評価の順番が決まっているようで決まっていないようで、何で tail の時だけ計算結果を再利用できるのだろう。これが分かればアニメーションの美しい表現方法が理解出来る気がすると思って頑張っている。

アランさんに以前言われたのが、シミュレーション言語で評価順序がどうあるべきかという問題。例えば二台の車 A, B が走っていて、お互いの座標で次の時刻の座標を決めるとする。ここで問題になるのが、B を見てる車 A と、A を見てる車 B の計算順序によって結果が変わってはいけないという事。これを不用意に書くと、A が動いた後の座標を元に B が動いてしまったりして、整合性が取れなくなる。

これは勿論「変更前」を念頭に置いて書けばいいだけの事なんだけど、正しい書き方があるとしたらどうかは面白い問題だ。一つのアイデアとしては、二つの命令の関係に「直列」と「並列」を導入したら良いんじゃ無いかと思う。

(並列 (A.動く: B) (B.動く: A)) -- 並列実行。両者は同時刻に前の座標を元に動く

(直列
  (A.動く: B)
  (B.動く: A)) -- 直列実行。A が動いてからその結果を元に B が動く

これが突飛なアイデアかというと、そうでもなくて、Haskell はこういう風に動く。つまり関数に(無限リストが無ければ)順序が影響しない一方、do による IO モナドは直列に評価され、後ろは前に影響される。さらに意外と変な感じがしないのは、昔の BASIC を思い出すから。

昔の BASIC は命令と関数が分かれていた。実行順序に面白い特徴は無かったけど、普通に両者は別の物だった。それが C 言語の頃から(僕の歴史では)、副作用のある命令の事も『関数』と言い出して話がややこしくなった。初めて C の関数を学んだとき、返り値が無くても『関数』というのはどうにも変な気がした。今でこそ『副作用のある関数』という考えに慣らされてしまっているけど、今にして思うとあの気持ち悪さは正当な物だった。

Haskell の面白いのは、副作用を司る IO モナド以外にも、リストにひっくるめた処理をする時とか、結果が定まらない時とか、地の文とちょっとでも性格の違う実行順序を表現するときに独自の表現が出来る所。そういったミニ言語と地の文を自然と混ぜる工夫がしてある。いや、イマイチ自然じゃないからモナドが難しいと意見が出てくるのかな。とにかく、その部分は絶対解決したい。

ストリームを関数で表現するって言っても関数なんだから、わざわざ簡単な物を難しく見てるだけなような気もするけど、もしかしてそこに命令と関数の本当に自然な関係が見えてきたら面白いなと思う。