setcar! って、レンタカー屋さんじゃないぞ | たけおか ぼちぼち日記

たけおか ぼちぼち日記

思いついたらメモ

これは、 Lisp SETF Advent Calendar 2018 - Qiita の DEC/21 の記事として書きました。


setcar! でググると、レンタカー屋さん と、バスなどを作ってる会社 が出てきた(^^;
なるほどっ!


純粋関数型が好きな 意識の高い人々からは、極めてバカにされている Lisp の setf などですが…
実際、副作用は良くないよね。並列化の邪魔だ。
(私は、TK80で遊び始めた頃から並列計算が好きです)

だが…
私は、setcar! (rplaca), setcdr! (rplacd) を使う。断じて使う。
(私はCommon Lispを書くことが多いので、rplaca/rplacd/setf を使う)


Lispで、プログラミング言語の実行系をつくるのは、誰もが、しばしば(バシバシと)行っているであろう。

・いにしえの素朴なLisp インタープリタを作るとき…
変数などのバインディング状況を環境として作り、その環境をリストでつないでいくであろう。

バインディングの表現方法によるが、変数の内容が更新された時、setcdr! (か、setcar!) を使うことになるであろう。
実現方法が素朴であり、それなりの実行速度を求め、かつ、プログラマが楽をしたければ。(^^;

また、関数呼び出しから戻るとき、
(C言語的な表現ならば、スタックを巻き戻すとき)
環境リストの新しいものを切り捨てて、古い方の環境を最新にする。
これも、環境リストの表現方法によるが…
環境リストの最新を保持する cons の carかcdr を set! する(つまり、setcar! か setcdr!する)
ことになるであろう。(環境リストを単純な変数で保持していたら、その変数にset!するだけだが)
大域脱出などで、環境リストを、いきなりたくさん縮めたいときに、setcdr! したい気持ちが高まる(であろう、たぶん…きっと…)。



・Prologインタープリタを Lispで作るとき…

Prologの変数は、双方向代入であり…
ず〜っとアンバウンド(未代入)の変数の値が、どんどん呼びだされた後の節の中で決まり(バインドされ)、
それが呼び出し側(環境リストでいうと浅い側の環境の中)の変数に反映されなければならない。
これは、もう、環境リスト中の変数の値を、set!(インタープリタの中では、setcdr!ぐらい)を、行うしかないっ!
(凡人の脳では)

そして加えて…
Prologが素晴らしいのは、バックトラックが行われた場合、
上記のような変数のバインディングは、キレイさっぱりと、忘れてしまわなければならないことである。
その実現を、素朴な凡人脳でプログラムすると、
環境リストの途中を setcdr! して、
忘れてしまいたいバインディングを保持した環境を、切り離してしまうことであろう。

うほほ〜い、setcar!/setcdr! 最高〜\(^^)/


・Schemeの setcar!/setcdr! が rplaca/rplacd でないのは…
私は、
「SchemeにMAC Lisp上に書かれていたものがあって、関数名がMAC Lispとぶつからないようにしてたのじゃないかな〜」
と、勝手に想像してます。



・ちなみに、Common Lisp の setfは、私の中では…
- 値を得る直前に、寸止めして、参照場所を見るだけとして堪え、
- そこに値をぶち込む
という行為に、
マゾ感覚(寸止めで我慢) と、
サド感覚(最後に、値をぶち込む)
の両者を感じ、大変に感情を揺さぶられる 魅惑的な機能として位置づけられている。
また、setfは、純粋関数に反した背徳的な行為であることも、その魅力を、指数関数的に増大させている。


もう、私は、setf/rplaca/rplacd 無しでは、退屈すぎて、クリスマスも自宅で寝るしかないのである。
(setf/rplaca/rplacd があっても、クリスマスは自宅で寝ると思われるが…)