アナフォリックマクロとpackage
アナフォリックマクロをpackageに分けて使う場合のメモ書き。
カレントパッケージで、定義・使用する場合
(defmacro a.when (expr &body body) `(let ((it ,expr)) (when it ,@body))) > (a.when (member 2 '(1 2 3)) (car it)) --> 2
特に問題なし。
定義と使用が別パッケージの場合
;;; マクロ定義パッケージ (defpacakge :test (:use :cl) (:export :a.when)) (in-package :test) ;; ... a.when定義 ... ;;; (in-package :cl-user) (use-package :test) > (a.when (member 2 '(1 2 3)) (car it)) --> エラー: 変数IT は定義されていない
エラーが出る。
解決策1: packageを明示的に指定
;;; ... defpackageとa.when定義 ... (in-package :cl-user) (use-package :test) ;; itのpackageを明示的に指定 > (a.when (member 2 '(1 2 3)) (car test::it)) --> 2
毎回修飾するのは嫌なので却下。
そもそも、internalなsymbolを使っているのは問題。
解決策2: itをexport
;;; マクロ定義パッケージ (defpacakge :test (:use :cl) (:export :a.when :it)) ; <- itもexport (in-package :test) ;; ...a.when定義... ;;; (in-package :cl-user) (use-package :test) > (a.when (member 2 '(1 2 3)) (car it)) --> 2
itもexportしてあげれば、普通に実行できる。
ただ、この方法だと、アナフォリックマクロを定義しているpackageを必ずuseしなければいけない。後、symbol競合の問題も若干あるかもしれない
;;; ... 略(itをexportする版) ... (in-package :cl-user) ;; (use-package :test) コメントアウト > (test:a.when (member 2 '(1 2 3)) (car it)) --> エラー: 変数IT は定義されていない
解決策3: itをマクロ展開時にintern
;;; マクロ定義パッケージ (defpacakge :test (:use :cl) (:export :a.when)) (in-package :test) ;; itをsymbol-macroとして定義 (define-symbol-macro it (intern "IT")) (defmacro a.when (expr &body body) `(let ((,it ,expr)) ; it -> ,it (when it ,@body))) ;;; (in-package :cl-user) > (test:a.when (member 2 '(1 2 3)) (car it)) --> 2
こんな感じで(マクロ展開時に)毎回internするようにすれば、アナフォリックマクロを定義しているパッケージをuse-packageするしないに関わらず、itをカレントパッケージのsymbolとして扱えるようになる。
この方法も問題があるかもしれないが、とりあえずは一番良さそうな気がする。