dynamic - 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))))))))
我的问题是:在宏中使用宏是否会自动禁止它是动态的?(我想是的......,因为宏定义中的宏调用必须在编译之前执行,不是吗?或者不是?)。
何时使用静态或动态宏解决方案?- 当然,如果数据仅在运行时已知,则需要一个动态宏,不是吗?什么是最佳实践?
解决方案
你误解我了。
当我说“静态”与“动态”时,我是在谈论由宏绑定的变量是在编译时(“静态”)还是仅在运行时(“动态”)已知。
一般来说,应该坚持使用“静态”,因为它会产生更易读的代码。唯一需要“动态”的情况是在创建 DSL(“特定领域的语言”)时。
使用“宏中的宏”是一个完全正交的问题。人们总是可以做到这一点(如果做得正确)。
推荐阅读
- powershell - 简单的 PowerShell 选择字符串模式
- java - Flink - 从数据库属性创建广播流
- vue.js - Vuejs - 获取动态生成的输入字段及其值并在更改时更改其颜色
- javascript - 将服务器上的 div 保存为图像并下载
- jenkins - 詹金斯是否可以在“一排”连续失败中只保留第一次和最后一次失败?
- powershell - 从 PowerShell 中的 Invoke-RestMethod 同时读取和写入同一文件
- java - Java使用正则表达式匹配器获取组
- python - 如何在不滚动的情况下在 jupyter notebook 中绘制所有图
- python - 如何在 python 中使用存储的变量进行发布请求
- reactjs - 当状态变量改变时使用 useQuery