如何检查变量是否在 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
)
(*) “特殊形式”是一个特别标记的原始函数,因此它的参数不会全部被评估。大多数特殊形式定义控制结构或执行变量绑定——函数不能做的事情。
每种特殊形式都有自己的规则,对哪些参数进行评估,哪些在不评估的情况下使用。是否评估特定参数可能取决于评估其他参数的结果。
我认为这样做的“规范”方式是
(let ((bound (boundp 'a))
(a t))
(unless bound (makunbound 'a))
...blabla...)