アナフォリックマクロと package
via アナフォリックマクロとpacakge(2) - sileのブログ
it も一緒に export しといて使う側は use-package する、で個人的には困らないかなと思うのだけど、ライブラリとしてはまるっと use-package しなくてもマクロだけパッケージ名付きで `(anaph:awhen ...)` と使いたいことはあるような気もする。そうすると it の所属パッケージがアナフォリックマクロを使うコードのパッケージになっちゃったりしてめんどいことに。
で、アナフォリックマクロを使う側で使ってる it を拾ってきて使い回せばいんじゃね?と思ってみた。
(defpackage :anaph (:use :lisp)) (in-package :anaph) (export '(awhen it)) ; いちおう export しておく (defun flatten (tree) (labels ((rec (x acc) (cond ((null x) acc) ((atom x) (cons x acc)) (t (rec (car x) (rec (cdr x) acc)))))) (rec tree nil))) (defun find-it-var (expr) (find-if (lambda (atom) (and (symbolp atom) ;; case insensitiveェ... (string-equal "IT" (symbol-name atom)))) (flatten expr))) (defmacro awhen (&whole whole test &body body) (let ((it-var (or (find-it-var whole) 'it))) (assert (symbolp it-var)) `(let ((,it-var ,test)) (if ,it-var (progn ,@body)))))
アナフォリックマクロの呼び出し式から "IT" という名前のシンボルを探して、見つかればそのシンボルを使う。見つからなかったら anaph:it を使う。
;; use-package して使う場合 (defpackage :test1 (:use :lisp :anaph)) ; anaph を use してるので => #<package: test1> (in-package :test1) => #<package: test1> (awhen (+ 1 2) (list '(+ 1 2) it)) ; この it は anaph:it => ((+ 1 2) 3)
;; use-package せずに使う場合 (defpackage :test2 (:use :lisp)) ; anaph を use してないので => #<package: test2> (in-package :test2) => #<package: test2> (anaph:awhen (+ 1 2) (list '(+ 1 2) it)) ; この it は test2::it だけど => ((+ 1 2) 3) (macroexpand `(anaph:awhen (+ 1 2) (list '(+ 1 2) it))) => (let ((it (+ 1 2))) ; test2::it を使うように展開される (if it (progn (list '(+ 1 2) it)))) => t
extended loop で使える it が似たようなことやってそうな予感。