Lisp 新手在这里。
我的目标是定义一个宏,它将使点列表的键可用作变量以访问相应的值,因此名称为»let-dotted-alist«。所以我想要的是:
(setq foo '((a . "aa") (b . "bb")))
(let-dotted-alist foo
(message (concat a b)))
==> "aabb"
这是迄今为止我能想到的最好的:
(defmacro let-dotted-alist (alist &rest body)
"binds the car of each element of dotted ALIST to the corresponding cdr and makes them available as variables in BODY."
`(let ,(nreverse
(mapcar
(lambda (p) (list (car p) (cdr p)))
(eval alist)))
,@body))
这里的问题是eval
. 我需要它以便能够将 alist 作为变量 ( foo
) 而不是文字传递,这是定义函数时的主要用例。为了让宏计算出代码,这个变量需要已经绑定。我仍然在任何地方读到使用 eval 往往表明代码中存在缺陷?有办法解决吗?
如果 Emacs 24 没有引入想要在加载时扩展宏的急切宏扩展,这将是一个有点学术问题,dotlist
而应该提供 alist 的变量(在以下示例中)仍然是无效的:
(defun concat-my-cdrs (dotlist)
(let-dotted-alist dotlist
(print (concat a b))))
根据我对此的评估方式,我要么得到»mapcar:符号作为变量的值是 void:dotlist«,要么得到 »Eager 宏扩展失败:(void-variable dotlist)«。这当然是有道理的,因为变量 dotlist 在加载时确实是无效的。
现在,在我尝试找到(本地)禁用急切宏扩展的解决方法之前,有没有办法改进宏定义以eval
完全避免这种情况?