【问题标题】:Dynamic macros in common-lisp - when and how to usecommon-lisp 中的动态宏 - 何时以及如何使用
【发布时间】:2018-11-12 19:26:54
【问题描述】:

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

How to wrap and execute a lisp s-expression by another s-expression?

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

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

(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))))))))

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

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

【问题讨论】:

  • DOLIST 是一个宏,您在动态版本中使用它。所以显然它并没有禁止它。
  • 你应该使用能产生最清晰的代码来解决问题的任何一种形式。
  • @Barmar true ...但是 with-open-files 禁止它...也许是因为它需要一个字面使用的参数? (例如流变量?) ...
  • 对。在运行时计算值时,不能使用需要编译时文字的宏。

标签: dynamic static macros common-lisp


【解决方案1】:

你误会了。

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

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

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

【讨论】:

  • 对于初学者常犯的“macro in macro”你知道哪些错误呢?
  • @Gwang-JinKim:主要错误是使用执行而不是宏扩展进行调试。
  • 谢谢!你什么时候觉得“你明白了”——你有过这样的时刻吗?
猜你喜欢
  • 2018-01-21
  • 2011-03-08
  • 2021-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-18
相关资源
最近更新 更多