首页 > 解决方案 > common-lisp 中的动态宏 - 何时以及如何使用

问题描述

在我之前的问题中,@sds 回答得非常好,

如何用另一个 s 表达式包装和执行一个 lisp s 表达式?

我们来到了动态和静态宏的话题。

with-open-files@sds对我的宏观问题的静态解决方案是:

(defmacro with-open-files ((streams file-names &rest options &key &allow-other-keys) &body body)
  (if (and streams file-names)
      `(with-open-file (,(pop streams) ,(pop file-names) ,@options)
         (with-open-files (,streams ,file-names ,@options)
           ,@body))
      `(progn ,@body)))

以及他的动态解决方案:

(defmacro with-open-files-d ((streams file-names &rest options &key &allow-other-keys) &body body)
  (let ((sv (gensym "STREAMS-"))
        (ab (gensym "ABORT-"))
        (op (gensym "OPTIONS-")))
    `(let ((,sv ,streams)
           (,ab t)
           (,op (list ,@options)))
       (progv ,sv (mapcar (lambda (fn) (apply #'open fn op)) ,file-names)
         (unwind-protect (multiple-value-prog1 (progn ,@body) (setq ,ab nil))
           (dolist (s ,sv)
             (when s
               (close s :abort ,ab))))))))

我的问题是:在宏中使用宏是否会自动禁止它是动态的?(我想是的......,因为宏定义中的宏调用必须在编译之前执行,不是吗?或者不是?)。

何时使用静态或动态宏解决方案?- 当然,如果数据仅在运行时已知,则需要一个动态宏,不是吗?什么是最佳实践?

标签: dynamicstaticmacroscommon-lisp

解决方案


你误解我了。

当我说“静态”与“动态”时,我是在谈论由宏绑定的变量是在编译时(“静态”)还是仅在运行时(“动态”)已知。

一般来说,应该坚持使用“静态”,因为它会产生更易读的代码。唯一需要“动态”的情况是在创建 DSL(“特定领域的语言”)时。

使用“宏中的宏”是一个完全正交的问题。人们总是可以做到这一点(如果做得正确)。


推荐阅读