Elisp:在let中绑定

kin*_*ero 3 emacs elisp let

如何在let构造之前或之内检查变量是否已定义?

 (let (((if (boundp 'a)
           'a
         'dummy) t))
   (message "I made this work"))
Run Code Online (Sandbox Code Playgroud)

我想要做的是检查之前是否a有界限,如果已经绑定,则将其绑定到t本地.否则根本不在乎a.

phi*_*ils 5

代码失败为:(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
  )
Run Code Online (Sandbox Code Playgroud)

缺点是,如果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))
Run Code Online (Sandbox Code Playgroud)

然后我意识到,就像许多事情一样,宏是答案:

(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
  )
Run Code Online (Sandbox Code Playgroud)

(*)"特殊形式"是一种特殊标记的原始函数,因此它的参数不会全部被评估.大多数特殊形式定义控制结构或执行变量绑定 - 功能无法做到的事情.

每种特殊形式都有自己的规则,可以对哪些参数进行评估,哪些参数在没有评估的情 是否评估特定参数可能取决于评估其他参数的结果.