gpt4 book ai didi

scope - 避免无意中使用照应宏的陷阱

转载 作者:行者123 更新时间:2023-12-04 13:30:29 25 4
gpt4 key购买 nike

我如何知道我是否在调用 anaphoric macro ?如果我在不知情的情况下这样做,一些看似未绑定(bind)的符号的行为可能与预期的完全不同。

例子

从列表中收集所有偶数很容易:

> (loop for i in '(1 2 3 4)        ;correct
when (evenp i) collect i)
(2 4)

但是,如果有人想到给迭代变量命名 it (因为“it”似乎是“item”的一个很好的缩写;C++ 的人也经常使用称为 it 的迭代器进行迭代),结果突然变得完全不同:
> (loop for it in '(1 2 3 4)         ;wrong
when (evenp it) collect it)
(T T)

这听起来可能有点做作,但最近发生了这样一个尴尬的错误,嗯,我认识的人。

那么如何避免再次陷入同样的​​陷阱呢?

最佳答案

这是照应宏不被一致喜欢的主要原因,人们通常会尽量谨慎地使用它们。显式绑定(bind),如 if-let在实践中似乎更被接受。

然而,据我所知,LOOP 宏是规范中唯一提供隐式绑定(bind)的构造,如果您认为它是相同的,则可能 NIL block 除外。此外,它已被广泛记录,并且不会很快改变。因此,给出的示例感觉有点人为。同时,不可否认,这种bug可能会发生。

So how to avoid this type of bugs?



也许你不需要做任何事情。错误会发生,但这种错误不太可能经常发生。

但如果您愿意,您可以决定限制语言以禁止使用 it在 LOOP 中(因为您担心您或其他人会引入相同的错误):
(defpackage mycl (:use :cl) (:shadows #:loop))
(in-package mycl)

上面定义了一个自定义的 CL 方言,它隐藏了 loop象征。 loop可以从包 MYCL 访问的符号(在没有给出包前缀时解决)是来自 MYCL 的符号,而不是 CL:LOOP。
然后,您可以添加自己的检查:
(defmacro loop (&body body)
(when (find "IT" body :test #'string=)
(error "Forbidden IT keyword"))
`(cl:loop ,@body))

该定义应该足够了(它可能会错过某些情况)。
然后,您选择在项目中使用此包而不是 CL,因此,以下失败并出现错误:
(defun test ()
(loop
for it in '(1 2 3 4)
when (evenp it) collect it))

...
error:
during macroexpansion of
(LOOP
FOR
IT
...).
Use *BREAK-ON-SIGNALS* to intercept.

Forbidden IT keyword

Compilation failed.

检查的另一种方法如下(通过尝试查看以 LOOP 为根的所有树更严格,因此即使对于其他有效情况也可能出错):
(defmacro loop (&body body)
(unless (tree-equal body (subst nil
"IT"
body
:test #'string=
:key (lambda (u)
(typecase u
((or symbol string) (string u))
(t "_")))))
(error "Forbidden IT keyword"))
`(cl:loop ,@body))

您可以将相同的方法应用于您发现有问题的其他构造,但请注意,通常照应宏是由外部系统带来的,这是有意完成的,因此不应让人感到意外。但是即使您不知道某些宏是照应,它们的文档甚至命名约定也应该足以防止错误(照应系统引入以 a 开头的符号,例如 aifawhen ,或 s ,如 scase )。
如果您在交互式环境中工作(例如 Emacs/Slime,但也有其他环境),则可以轻松地显示附加到函数或宏的文档。

关于scope - 避免无意中使用照应宏的陷阱,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51621005/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com