Island Life

< 高校受験 |

2021/10/05

無限cxr

carcdrの合成 (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

Name: