如何根据 elisp 中的一个条件设置一堆变量?

how to set a bunch of variables depending on one condition in elisp?

假设我想根据一个条件设置 barbaz 的值,这在两种情况下都是相同的,比如说 foo 的值。使用 let 特殊形式,我做这样的事情

(let ((bar (if foo 1 2))
      (baz (if foo 3 4)))
  ... )

虽然上面的程序是正确的,但看起来有点奇怪,因为它检查了两次foo的值。在这种情况下是否可以使用惯用语来避免双重检查?

您可以使用 cl-lib.el 提供的多个值,Emacs 的 Common Lisp 扩展:

(multiple-value-bind (bar baz) 
    (if foo (values 1 3) (values 2 4))
  ...)

您可能希望在不同的函数中提取这两种情况。

我在 elisp 中唯一能想到的答案(没有多个值)是这样的相当可怕的东西:

(apply (lambda (bar baz)
         ...)
       (if foo
           (list 1 2)
         (list 3 4)))

这通常很方便,尽管在可以提供文字列表的良好情况下显然不需要这样做。

你可以把它包装在一个宏中:下面就是这样,尽管它迫切需要一些错误检查(elisp 太烦人了,我不想花更多的时间在它上面——至少它有现在反引号)。

(defmacro plet (vars-vals &rest forms)
  `(apply (lambda ,(car vars-vals)
            ,@forms)
          ,(cadr vars-vals)))

然后你的表达式将变成(这次使用文字列表)

(plet ((bar baz) (if foo '(1 2) '(3 4)))
  ...)

您不需要在 let 表单本身中设置值。 let 形式创建本地绑定,之后您可以根据需要设置值。

(let (bar baz)
  (if foo
      (setq bar 1
            baz 2)
    (setq bar 3
          baz 4))
  ...)