2021/10/05
無限cxr
「carとcdrの合成 (car, caddr, cadddr,...)って4段階までしか無いのか」ってツイートを見かけたので、無限に合成されるのを作ってみた。
あらかじめ定義しておかなくても、ソースコードを読んだ時点で展開されるので、
いくらでも長いc[ad]+rを使える。
これを使えば『Land of Lisp』のビリーとボブの会話も実行できるぞ!
(setf *readtable* *cxr-readtable*)
;;「ジブラルドルのエメラルド」が今週末に超特急列車で運搬される
(defparameter *train*
'((controls)
(empty security-camera)
(gem)
(empty guard1 empty empty guard2)
(passenger-seat passenger-seat passenger-seat passenger-seat)))
;; こう言えばいいかな。ブツは列車のCADDRにある
(caddr *train*)
; => GEM
;; それからセキュリティカメラが、つまり、列車のCADADRにある。
(cadadr *train*)
; => SECURITY-CAMERA
;; ここに、列車のCADDDDRに乗れる乗車券を買ってあるから
(caddddr *train*)
; => (PASSENGER-SEAT PASSENGER-SEAT PASSENGER-SEAT PASSENGER-SEAT)
;; でもこのCADADDDRとCADDDDADDDRにいる警備員はどうするのさ???
(list (cadadddr *train*)
(caddddadddr *train*))
; => (GUARD1 GUARD2)
なお、これを作ってたら"Land of Lisp"翻訳版のtypoに気づいた (最後のDが一個多かった)。やはり文中のコードは全て実行して検証すべきであるな。
ちなみにこの実装だと、クオートされたリテラル中にcaadddaddarみたいのが出てきた時にちょっとまずいことになる。それを回避するにはcxr-reader中で無理くりシンボルへの束縛を作っちゃう手がある。例えば expand-cxr を下のものと入れ替える。
ただ、規格上、マクロ文字リーダは(streamから読む以外の)副作用を持ってはならない、とされているので、厳密にはよくない。とはいえその規程はリスタートなどで複数回リーダが呼ばれた場合に動作を保証するためのものなので、冪等な副作用なら問題にはならないだろう。
Tags: Lisp, CommonLisp, LandOfLisp

Post a comment