【发布时间】:2019-06-30 03:14:34
【问题描述】:
我正在尝试创建类似于with-eval-after-load 的东西,除了在提供所有功能后对主体进行评估。此外,必须在运行时提供功能列表。
例如,我想要类似的东西
(setq feature-list '(a b))
(something feature-list (message "a and b both provided"))
它执行的功能等同于
(with-eval-after-load 'a
(with-eval-after-load 'b
(message "a and b both provided")))
在运行时提供列表似乎是棘手的部分。如果没有这个要求,我可以写一个宏:
(defmacro eval-after-load-all (features body)
(if (null features)
body
`(with-eval-after-load (quote ,(car features))
(eval-after-load-all ,(cdr features) ,body))))
并通过以下方式传递列表:
(eval-after-load-all (a b) (message "a and b both provided"))
但是传递feature-list 会导致它使用文字字符“功能列表”。
我试过定义一个递归函数:
(defun eval-after-load-all (features body)
(if (null features)
body
(with-eval-after-load (car features)
(eval-after-load-all (cdr features) body))))
但是当我评估时
(eval-after-load-all feature-list (message "a and b both provided"))
(provide 'a)
;; (provide 'b)
它在(provide 'a) 调用中触发错误,在递归调用步骤(即函数中的最后一个表达式)中抱怨void-variable body。这个范围让我感到困惑。为什么body 在这里无效?
我还尝试将宏包装在一个函数中,以便可以将评估参数传递给它:
(defun macro-wrapper (features body)
(eval-after-load-all features body))
但这在函数定义中抱怨features 不是一个列表:wrong-type-argument listp features。
【问题讨论】:
-
看看函数
eval-after-load- 它在运行时可能比宏更容易使用。 -
也许您的问题可以通过提供一个需要 A 和B 的模块“my-module”来解决(或者遍历一个列表并全部需要它们)?这样你只需要
(with-eval-after-load 'my-module ...)? -
不幸的是,我的用例与此相反。 A 和 B 可能尚未提供,在这种情况下 require 会发出错误信号。
-
我目前正在为每个功能使用 with-eval-after-load 并使用谓词保护代码。这种工作,但除了需要知道是否提供了所有功能之外,谓词还需要知道其他 eval-after-loads 是否已执行其代码,如果是则不执行。一旦受保护的代码执行完毕,就会提供另一个功能,所以也许我可以对其进行测试,但这开始感觉像是一种竞争条件(或者至少我不确定 emacs 是如何处理这种事情的)。
-
竞争条件是,受保护的代码是在调用其他 with-eval-after-loads 之前还是之后完成执行。