ファイルの末尾まで利くannotation
昔に記事にもした cl-annot-revisit というライブラリを、ちょっと前に Quicklisp に収録 してもらった。
なんか空いていた Lisp Advent Calendar 2022 の記事として、 cl-annot-revisit に搭載したしょうもない機能について書いておこうと思う。
@
リーダーマクロ
cl-annot-reivisit は、他の言語でよくある @
によるアノーテーションっぽく見える記法を導入するライブラリである。
@
リーダーマクロは、 @
直後にある form の末尾に、 その次にある form を1つ 追加する。
例えば以下のように書くと:
@(eval-when (:compile-toplevel :load-toplevel :execute)) (defun hello () "Hello, World!")
以下のように、 eval-when
の中に defun
が展開される。
(eval-when (:compile-toplevel :load-toplevel :execute) (defun hello () "Hello, World!"))
@
リーダーマクロがやってるのはこの並び替えだけで、各 form をどう扱うのかは @
の展開後のオペレータに丸投げしている。
別に toplevel を特別扱いしていないので、関数の中で使ってもいい:
(defun hello-string (name) @(with-output-to-string (stream)) (format stream "Hello, ~A!" name)) (hello-string "hoge") ; => "Hello, hoge!"
また、展開結果がマクロである必要もなく、関数呼び出しになってもよい。
あと略記法として、 @
の直後にシンボルが現れた場合は、そのシンボルをオペレータと思って呼び出すことにしている:
(defun inverse-number (n) ;; 関数 `cl:/' の呼び出し。 (/ n) と等価。 @/ n) (inverse-number 100) ; => 1/100
何個 form を取ってもいいよね
@
リーダーマクロは、 その次にある form を1つ 追加するものであった。
でも 別に1個に限る必要もない ように感じられる。そこで、 dispatching macro char なら整数引数を取れることを使い、追加する form の数を指定できるようにした #n@
リーダーマクロを用意した。
以下は二つの form に作用する例:
#2@(eval-when (:compile-toplevel :load-toplevel :execute)) (defun hello-world-1 () "Hello, World! (1)") (defun hello-world-2 () "Hello, World! (2)")
これは、以下のように展開される。
(eval-when (:compile-toplevel :load-toplevel :execute) (defun hello-world-1 () "Hello, World! (1)") (defun hello-world-2 () "Hello, World! (2)"))
&body
を取るマクロや &rest
を取る関数には便利かもしれない。 (しかし ()
で括った方が自明だろう。)
EOF まで作用してもいいよね
これまでのリーダーマクロは個数を指定していたが、 別に何個読んでもいい のかなと思った。
そこで、 #@
リーダーマクロを整数引数を渡さずに呼んだ場合、 EOF か )
が出るまで read
して括るようにしてみた。
例えば以下のように書くと、冒頭の eval-when
を EOF まで作用させることが出来る。
#@(eval-when (:compile-toplevel :load-toplevel :execute)) (defun hello-world-1 () "Hello, World! (1)") (defun hello-world-2 () "Hello, World! (2)") (defun hello-world-3 () "Hello, World! (3)")
また、 )
まで集めることを利用して別の form の一部で作用することも出来る:
(string= "abcABC123" ;; 以下は (concatenate 'string "abc" "ABC" "123") と等価 #@(concatenate 'string) "abc" "ABC" "123") ; => T
用途はない
実際のところ、素直に括弧でくくればいいところ、 こんなリーダーマクロを使ってコードを書く必要がない と思うので、用途はないと思う。
なんかノリで実装しただけの機能を紹介するという記事でした。