Emacs Lisp 宏不会扩展 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)返回t

错误可能是有一些简单的解决方案,但我只是找不到它。

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

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

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

检查它(sequencep my-vars-alist)返回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-xpp-macroexpand-last-sexp)。

看起来您要做的是将 alist 的键绑定到它们的值,这样您就可以将这些键用作 let 正文中的变量。 在最近的 Emacs 中有一个内置的宏:

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

最新更新