言語ゲーム

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

Twitter: @propella

関数型 LOGO: レシーバーは最後の引数であるべきだという話

この忙しいのに超素晴らしいと思えるアイデアを思いついてしまったので忘れないように書く。普通、オブジェクト指向言語のメソッド呼び出しを関数として考える時、レシーバ (self や this) は最初の引数として考えるでしょう。あれ駄目。レシーバは最後の引数です。

やりたい事。

複数のタートルが扱える LOGO を非正格の関数型言語で実装したい。なぜかというのは今度書きます。

内容

triangle =
  forward 100
  turn 120
  forward 100
  turn 120
  forward 100
  turn 120

例えばこのような文があった場合、これは副作用を含むので関数型言語では有り得ないと思うわけです。一見。でも例えば forward 100 を forward step trail をカリー化した物だと考えます。この場合 trail はタートルの軌跡を現すリストです。例えば [ [位置, 方向], [位置, 方向], ...] 。Trail を画面上の唯一のタートルの軌跡だとすると、以下のように書けます。

triangle trail =
  turn 90 (forward 100 (turn 120 (forward 100 (turn 120 (forward 100 trail)))))

traiangle Trail -- 三角形が表示される。

つまり、一見副作用のあるコマンドのリストっぽい文が並んでいる時、それをカリー化された関数適用の構文糖と解釈すればすっきりするという事です。結果は三角形を現すリストが返るので、それを表示すれば良いです。遅延評価を使えば、じわじわと先頭からアニメーションで三角形が出来る様子を表示させる事も出来るでしょう。

次に、receiver.message(arg ...) を (message args ... receiver) の構文糖と考えます。すると上記の関数は redTurtle.triangle や blueTutle.triangle のように複数のタートル(trail)に対して使う事が出来ます。

まとめと課題

レシーバを関数の最後の関数だと考えると、オブジェクト指向プログラムをすっきり関数型言語で表現できる。しかし、複数のオブジェクトが関係する処理をどうやって書けば良いか考え中。

追記: なぜ関数型言語の LOGO を実装したいか。

を書き出すと長くなるので、一点だけ。わたし制御構造に使われるブロックや特殊構文が嫌いなのです。つまり if や while を構文じゃなくて関数として書きたい。しかも余計な [] や {} を入れずすっきり書きたい。非正格な言語ならそれが可能です。非正格な言語で副作用を許すと破綻するので関数型言語になってしまう。モナドで良いかと言われると、object.message を object >>= message と思うって事かな?悪くないです。