如何在Emacs Lisp中动态构造可正常执行的lambda函数内容
问题根源
你当前实现失效的核心原因是反引号的作用位置错误:你把代码拼接的反引号写在了返回的lambda函数内部,导致lambda被调用时,只会返回拼接完成的代码列表,不会对这段代码做实际求值,因此直接输出了when结构的列表字面量。
可行实现方案
方案1:构造阶段直接拼接完整lambda(推荐)
把反引号移动到lambda外层,在调用make-anonymous-func时就把传入的逻辑拼接到lambda的函数体中,直接生成完整可执行的匿名函数,没有额外运行时开销。
正确实现代码:
(defun make-anonymous-func (&rest body) (interactive) `(lambda (arg) (when (not (string-empty-p arg)) ,@body (message arg))))
调用时注意不要给传入的自定义逻辑加单引号(加引号会把代码变成普通列表数据,无法作为执行逻辑拼接),示例:
;; 正确调用,执行后会依次输出"foo"、"bar" (funcall (make-anonymous-func (message "foo")) "bar")
用这个方案生成foo、bar函数的写法非常简洁:
(defun foo () (interactive) (make-anonymous-func (message "foo"))) (defun bar () (interactive) (make-anonymous-func (message "bar")))
方案2:lambda运行时动态eval代码
如果你需要保留原来传引用代码列表的调用习惯,或是需要根据lambda运行时的动态状态调整执行逻辑,可以在lambda内部用eval强制对拼接完成的代码列表求值。
实现代码:
(defun make-anonymous-func (&rest body) (interactive) (lambda (arg) (eval `(when (not (string-empty-p arg)) ,@body (message arg)))))
这种写法兼容你原来的调用方式:
(funcall (make-anonymous-func '(message "foo")) "bar")
注意这个方案每次调用生成的lambda时,都会重新拼接代码、执行eval,运行开销比方案1高,没有特殊需求优先选方案1。
内容的提问来源于stack exchange,提问作者tipotto
相关产品推荐
相关产品推荐

