循环宏中的常见 Lisp 绑定
Posted
技术标签:
【中文标题】循环宏中的常见 Lisp 绑定【英文标题】:Common Lisp Binding in Loop Macro 【发布时间】:2016-01-30 09:20:01 【问题描述】:我想在循环中重新绑定一个特殊变量。现在,通常这是使用let
完成的。
(let ((*read-eval* nil))
(do-something-here))
但是由于loop
宏有这些很好的with
子句,我想我可以在那里这样做。表达式(macroexpand '(loop with *read-eval* = nil))
最终将绑定扩展到let
,因此它肯定会专门用于我的实现。但我在the standard 中找不到任何表明这是标准化行为的内容。所以,我想,我的问题是:
(loop with *read-eval* = nil
for i from 1 to 10
do (something-involving-the-read-function))
修改现有的*read-eval*
变量是否需要符合要求的实现,或者是否存在创建同名新词法变量的风险?
【问题讨论】:
【参考方案1】:*read-eval*
是一个全局特殊变量。没有办法撤消它,即为它创建一个本地词法绑定。
with
子句被描述为使用bindings(而不是仅仅设置),这意味着,确实,一旦循环完成,我们将回到原始值(回答@joshua-tailor 的问题)。
让我们理性思考。 (loop with foo = nil ...)
确实为foo
建立了绑定。因此,对于(loop with *read-eval* = nil ...)
不 建立该绑定,实现必须检查(在宏扩展或编译时)*read-eval*
在运行时是否将是dynamic variable。这听起来很疯狂。
【讨论】:
这是真的,但仍然不清楚 loop 必须重新绑定,而不是仅仅分配。我们是否知道一旦循环完成,我们就会回到原来的值?我很确定答案是肯定的,基于lispworks.com/documentation/HyperSpec/Body/06_abb.htm,它表示变量不再存在于循环之外。措辞对于特殊变量不是特别好,但看起来唯一合理的解释是名称的本地绑定,这意味着 let(或 lambda,等)。以上是关于循环宏中的常见 Lisp 绑定的主要内容,如果未能解决你的问题,请参考以下文章
在宏中循环 3 个操作查询,直到第 4 个选择查询不返回任何记录