【发布时间】:2012-04-05 14:25:57
【问题描述】:
如何检查变量是否在 let 构造中定义?
(let (((if (boundp 'a)
'a
'dummy) t))
(message "I made this work"))
我要做的是检查a 之前是否有界,如果已经有界,则在本地将其绑定到t。否则根本不关心a。
【问题讨论】:
如何检查变量是否在 let 构造中定义?
(let (((if (boundp 'a)
'a
'dummy) t))
(message "I made this work"))
我要做的是检查a 之前是否有界,如果已经有界,则在本地将其绑定到t。否则根本不关心a。
【问题讨论】:
代码失败并显示:(wrong-type-argument symbolp (if (boundp (quote a)) (quote a) (quote dummy))),表明 let 特殊形式* 不会评估该参数(尽管该列表将评估为符号,但列表 本身 不是符号)。
这是一个简单但有缺陷的替代方法,它为 a 创建一个本地绑定,但如果它最初是未绑定的,则在该本地范围内取消绑定。
(let ((a (if (boundp 'a) t nil)))
(or a (makunbound 'a))
;; do things
)
缺陷在于,如果 a 最初是未绑定的,您会希望在该本地范围内分配给 a 的时间超过本地范围,而这种方法不会。
最初我认为您需要完全放弃 let 才能解决该问题,而只需使用以下内容:
(when (boundp 'a)
(setq a-backup a
a t))
;; do things
(when (boundp 'a-backup)
(setq a a-backup)
(makunbound 'a-backup))
然后我意识到,与很多事情一样,宏就是答案:
(defmacro let-if-bound (var value &rest body)
"Bind variable VAR to VALUE only if VAR is already bound."
(declare (indent 2))
`(if (boundp ',var)
(let ((,var ,value))
,@body)
(progn ,@body)))
(let-if-bound a t
;; do things
)
(*) “特殊形式”是一个特别标记的原始函数,因此它的 并非所有参数都被评估。大多数特殊形式定义控制 结构或执行变量绑定——函数不能的东西 做。
每种特殊形式都有自己的参数评估规则 并且无需评估即可使用。一个特定的论点是否 评估可能取决于评估其他参数的结果。
【讨论】:
(if (boundp var 是宏的一部分,而不是宏发出的形式。这意味着宏发出的表单将取决于编译时 var 的值,而不是运行时。
我认为这样做的“规范”方式是
(let ((bound (boundp 'a))
(a t))
(unless bound (makunbound 'a))
...blabla...)
【讨论】:
a 的 assignments 在任何一种情况下都不会在该范围的退出中存活,因此您是使用这种方法还是宏取决于您的“不”级别关心'a,如果以前没有绑定的话。