将变量暴露给从 defun 中返回的 lambda

Exposing variables to a lambda returned from within defun

我正在尝试附加一个密钥处理程序,以便首先执行包装函数来检查是否已加载库,如果没有,则在最终执行预期函数之前加载它。

想法是可以做到:

(global-set-key (kbd "C-c r")
                (run-or-load-f 'visual-regexp 'vr/replace))

其中 run-or-load-f 是:

(defmacro run-or-load-f (mode func)
  `(lambda()
     (interactive)
     (run-or-load mode func)))

我遇到的问题是 我不知道如何在上面的 lambda 中公开 modefunc。我什至不确定我是否需要一个宏,但看起来确实如此。

为了完成,上面的函数run-or-load非常简单:

(defun run-or-load (mode func)
  (unless (fboundp mode)
    (load-library (symbol-name mode)))
  (call-interactively func))

事实证明,我在调用 run-or-load 时不得不使用不同的语法,它允许 lambda 像闭包一样工作:

(defmacro run-or-load-f (mode func)
  `(lambda()
     (interactive)
     (run-or-load ,mode ,func)))

不,您的回答允许 lambda 像闭包一样运行”。

要使 lambda 像闭包一样运行,请在文件的第一行将 lexical-binding 作为文件局部变量打开。参见 Elisp 手册,节点 Lexical Binding.

你的答案使用带逗号的反引号,是用替换这些变量的值来代替 lambda 中的变量。也就是说,它删除了那些自由变量,用它们在构建(评估)lambda 时 .

的值替换它们

这里使用闭包的优点是 变量在函数被调用时可用(而不仅仅是在定义时)。 (如果你当时不需要变量那么这个优势就消失了。)

如果您使用 defun 而不是 defmacro 那么闭包的另一个优点是生成的函数可以在编译文件时自动进行字节编译。

相比之下,使用反引号 lambda 方法,字节编译时的结果只是一个列表:(lambda ...)。编译器无法知道您打算始终将该列表用作一个函数,因此它不会被编译成一个函数——每次调用该函数时它都会被评估为一个列表。 (除非你显式调用字节编译器来编译它。)