###test
#######Allegro Common Lisp の Modern Mode で読めなくなるコードとそれへの対処
https://y2q-actionman.hatenablog.com/entry/2024/12/24/Allegro_Common_Lisp_%E3%81%AE_Modern_Mode_%E3%81%A7%E8%AA%AD%E3%82%81%E3%81%AA%E3%81%8F%E3%81%AA%E3%82%8B%E3%82%B3%E3%83%BC%E3%83%89%E3%81%A8%E3%81%9D%E3%82%8C%E3%81%B8%E3%81%AE%E5%AF%BE%E5%87%A6
########aifの通常の定義は、aifをエクスポートするパッケージ (UTIL) とaifを使用するパッケージ (USER) とが同一でないとうまく使えないのですね。
```
; caught WARNING:
; undefined variable: USER::IT
```
つい先ほどこの罠に引っかかりました。
現代でアナフォリックマクロを定義するときのベストプラクティスはあるのでしょうか?
#キーワードにするシンボル特有の問題ですが、標準のLOOPのキーワード(forなど)はどこのパッケージで使っても大丈夫なような工夫があります。具体的には名前の文字列で比較するようにしています。
#他には、
・read時に確定するようにする
・キーワードはkeywordシンボルを使う
・(共有場所として)cl-userのシンボルを使う
・専用のパッケージを使う
別のアプローチとしては、
・アナフォリックマクロは使わない(when-letあたりにする)
あたりかと思います。
#;; read時にinternする
(defmacro aif (pred con &optional alt)
(let ((it (intern "IT" *package*)))
`(let ((,it ,pred))
(if ,it ,con ,alt))))
#個人的にはアナフォリックマクロは実際のコードでは使われていないので(話題になる程には)、when-letあたりを使うようにしています。
#ありがとうございます。確かに、LOOPマクロにも特殊用途のシンボルがありますね。
*package*というものを使うとリード時にシンボルを構成することもできるのですね。入門中の身なので生兵法で使うのがちょっと怖いですが、分かって使う分にはかなり便利そうです。
アナフォリックマクロを使わないというアプローチはとても明快ですね。こちらを採用してみます。
#####and-let* のそれ、自分はいつもこんなふうに書いてます。
(and-let* ([n (expr)]
[ (even? n) ]) ; 束縛変数が無い場合
..)
#値に#fが使えないのはまあ、generalized booleanをモナドもどきに使う宿命なんで、and-let*に限らない気が。
#(and-let* ((even? n)) ...) の方の問題は未使用のローカル変数を警告する支援があれば気付けそう、と思って確認してみると、(and (let ((even? 42)) (and even?)))と展開されるから気付けないのか……。
#