APROGNの実装色々 — #:g1

Posted 2010-10-29 14:53:00 GMT

先日のエントリーでAPROGNというアナフォリックなPROGNを突然定義して使ってみましたが、

(defmacro aprogn% (&body body)
  `(let (it)
     (setq ,@(mapcan (curry #'list 'it)
                     body))
     it))

;; マクロ展開 (aprogn% 1 it) ⇒ (LET (IT) (SETQ IT 1 IT IT) IT)

みたいな感じでSETQに展開するものでした。
これはこれでOKかなと思いましたが、他にも何パターンか考えてみました。
LETに展開
(defmacro aprogn%% (&body body)
  (if (null body)
      'it
      `(let ((it ,(car body)))
         (aprogn%% ,@(cdr body)))))

;; マクロ展開 (aprogn%% 1 2 3 it) ⇒ (LET ((IT 1)) (LET ((IT 2)) (LET ((IT 3)) (LET ((IT IT)) IT))))

LET*に展開
(defmacro aprogn%%% (&body body)
  `(let* (it
          ,@(mapcar (curry #'list 'it)
              body))
     it))

;; マクロ展開 (aprogn%%% 1 2 3 it) ⇒ (LET* (IT (IT 1) (IT 2) (IT 3) (IT IT)) IT)

ITを直前の式で置換
(defmacro aprogn%%%% (&body body)
  (reduce (lambda (ans x)
            (subst ans 'it x :test #'equal))
          body))

;; マクロ展開 (aprogn%%%% (write-to-string '([])) (ppcre:regex-replace-all "\\[" it "(") (ppcre:regex-replace-all "\\]" it ")") (read-from-string it))

⇒ (READ-FROM-STRING (PPCRE:REGEX-REPLACE-ALL "\\]" (PPCRE:REGEX-REPLACE-ALL "\\[" (WRITE-TO-STRING '([])) "(") ")"))

最後のだけ動作が違いますが、やりたいこととしては入れ子を展開することが目的なので、一番あっている気もします。
しかし、これだとPROGNという名前は良くないのかもしれない…。

comments powered by Disqus