gpt4 book ai didi

emacs - Elisp : Macro expansion at load time with eval of undefined variable

转载 作者:行者123 更新时间:2023-12-02 01:22:11 25 4
gpt4 key购买 nike

这里是 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) 而不是文字传递,这是定义函数时的主要用例。为了让宏计算出代码,这个变量需要已经绑定(bind)。仍然到处都是我读到的,使用 eval 往往表明代码中存在缺陷?有解决办法吗?

如果 Emacs 24 没有引入 eager macro expansion 想要在加载时扩展宏,当变量(下例中的 dotlist)应该提供该列表仍然无效:

(defun concat-my-cdrs (dotlist)
(let-dotted-alist dotlist
(print (concat a b))))

根据我对此的评估方式,我要么得到 »mapcar:Symbol's value as variable is void: dotlist« 要么 »Eager macro-expansion failure: (void-variable dotlist)«。这当然是有道理的,因为变量 dotlist 在加载时确实是空的。

现在,在我尝试按照(本地)禁用急切宏扩展的思路找到解决方法之前,是否有任何方法可以改进宏定义以完全避免 eval

最佳答案

首先,我会提到 eager-macroexpansion 不会引入新问题:如果您尝试对文件进行字节编译,同样的问题会出现在早期的 Emacsen 中。

至于避免 eval,您可以通过使用其他使用 eval 的方法,例如cl-progv:

(defmacro let-dotted-alist (alist &rest body)
(macroexp-let2 nil alist alist
`(cl-progv (mapcar #'car ,alist)
(mapcar #'cdr ,alist)
,@body)))

但请注意语义有点不同:变量只能是动态作用域而不是词法作用域,因为变量列表只有在运行时才知道。

关于emacs - Elisp : Macro expansion at load time with eval of undefined variable,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39377820/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com