Emacs Lisp 宏不展开 Alist

Emacs Lisp Macro Does Not Expand Alist

这是我的宏,它应该做的是用 vars-alist

的绑定将 body 包装在 let
(defmacro with-vars-alist (vars-alist &rest body)
  `(let (,@(mapcar (lambda (cell) (list (car cell) (cdr cell))) vars-alist))
     ,@body))

当我查看它使用以下代码扩展的内容时

(defvar my-vars-alist '((var1 . "var1")
                        (var2 . "var2")))
(macroexpand-1 (with-vars-alist my-vars-alist `(concat ,var1 ,var2)))

我得到一个错误 cons: Wrong type argument: sequencep, my-vars-alist

但是检查它 (sequencep my-vars-alist) return t

这个错误可能有一些简单的解决方法,但我就是找不到。

请记住,宏的参数是 未计算的,这意味着当您将 my-vars-alist 作为参数传递时,它会作为 [=45= 逐字传递]符号 my-vars-alist.

因此在宏扩展期间,vars-alist 计算为符号 my-vars-alist 而不是列表 ((var1 . "var1") (var2 . "var2")).

所以错误不是抱怨 变量 my-vars-alist 没有 包含 一个序列作为它的值,而是 符号 my-vars-alist 不是 本身 序列(这是正确的 - 它是一个符号)。

checking it (sequencep my-vars-alist) return t.

这也是正确的,因为 my-vars-alist 被评估为其值 ((var1 . "var1") (var2 . "var2"))

的变量

所以你需要eval那个论点。例如:

,@(mapcar (lambda (cell) (list (car cell) (cdr cell)))
          (eval vars-alist))

由于 vars-alist 已经 被计算为符号 my-vars-alist,此更改意味着我们正在将符号 my-vars-alist 传递给 eval,它将其作为一个变量求值以获得 mapcar.

所需的列表

您可能还想引用传递给 macroexpand-1 的表单(或使用 M-x pp-macroexpand-last-sexp)。

我看起来像你想做的是让一个列表的键绑定到它们的值,这样你就可以在 let 主体中使用这些键作为变量。在最近的 Emacs 中有一个内置的宏:

(let-alist '((a . 1) (b . 2))
  (message "a: %d, b: %d" .a .b))