なぜラムダ計算なのか

絵を描く行為の抽象化として「絵を描かせる為の『状態 (= キャンバス)』に対する破壊的操作の手順を記述する」よりも 「その絵が何たるかを宣言的に書き下す」ほうが、自身の手で主体的に絵を描くという身体感覚から離れないんじゃなかろうかと最近思ってる https://twitter.com/_baku89/status/1405746340169093123

遅延評価、強い型付け、逐次実行の概念や副作用の無い、関数型で、シンタックスだけS式のプログラミング言語が、俺の考える最強の映像制作環境に必要 https://twitter.com/_baku89/status/1445029552992886786

人の手に代わってカキカキしてくれる描画コンテクストに対して命令列を与えるという距離感は、画材としての手触りを鈍くさせる気がする。「描く」というより「描いてもらう」に近い。ラムダ計算の方が「どういう手順で描くか」ではなく「それ自身が何なのか」を直に描き下せるので、デザイン向きだと思える。

Glispにおける

(stroke "blue"
  (rotate (deg 45)
    (line [0 0] [100 0])))

は、 (((線)を(45度)回転させたもの)の青いやつ)という、グラフィックの状態を述べた文であって

stroke("blue")
rotate(toDeg(45))
line(0, 0, 100, 0)

のように、一文ずつ逐次実行される命令ではない。

Glispのコードは、あるグラフィックを描くための手順を記した「アルゴリズム」ではい。そのグラフィックそのものの姿形の記述。つまり、そこには「現在適用されている線色・トランスフォーム」というステートの概念が必要無い。ゆえに pop/pushMatrixも必要なければ、「noStroke() を呼び出すとそれ以後の描画の線が消える」というような文の前後関係も無い。

プログラムでありながら、その構文木をIllustratorのレイヤーツリーのように表現したとて、違和感がない。関数名を命令形にするという慣例すら、Glispの特徴を捉えづらくするのかもしれない。(with-stroke "blue" (rotated ... の方がしっくりくる。

操作的意味論と表示的意味論

Wikibooksのこの記事が面白かった。Haskell/Denotational semantics

Cretive codingと日々のチマい映像制作やデザイン行為を統合しづらい一つの技術的理由は、前者の現状は命令型/操作的意味論の世界なのに対して、後者は表示的意味論の領域だからだと思っている。

参照透過性

プログラミング言語の参照透過性は、テストが書きやすくなる、安全性が高くなるという実用上のメリットをもたらすだけではない。プログラミングという概念そのものを、表示的意味論の世界に近づける。

手続き型言語に慣れている方は、「関数」と聞くと「再利用できるようモジュール化された一連の手続きの塊」を思い浮かべるかもしれない。例えば、p5.jsで「ある中心をもつ正方形」を描くうちに、それを関数にまとめたくなる。こんなふうに:

function drawSquareWithCenter(cx, cy, width) {
	rect(cx - width/2, cy - width/2, width, width)
}