我正在尝试附加一个密钥处理程序,以便首先执行一个包装函数,检查是否已加载库,如果没有,则在最终执行预期函数之前加载它。
我们的想法是:
(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中公开mode
和func
。我甚至不确定我需要一个宏,但看起来确实如此。
为了完成起见,上面的函数run-or-load
非常简单:
(defun run-or-load (mode func)
(unless (fboundp mode)
(load-library (symbol-name mode)))
(call-interactively func))
答案 0 :(得分:3)
不,你的回答不“允许lambda充当闭包”。
要使lambda像闭包一样,打开lexical-binding
作为文件第一行的文件局部变量。请参阅Elisp手册,节点Lexical Binding。
你使用反引号和逗号的答案是替换这些变量的值来代替lambda中的变量。也就是说,它删除了那些自由变量,将它们替换为构造(评估)lambda时的值。
这里使用闭包的好处是,在调用函数时变量可用(不仅仅是在定义它时)。 (如果那时你不需要变量那么这个优势就会消失。)
如果您使用defun
而不是defmacro
,则闭包的另一个优点是,在编译文件时,结果函数可以自动进行字节编译。
相反,使用反引用的lambda方法,字节编译时的结果只是一个列表:(lambda ...)
。编译器无法知道您打算始终将该列表用作函数,因此它不会编译为函数 - 每次调用函数时都会将其计算为列表。 (除非你明确地调用字节编译器来编译它。)
答案 1 :(得分:1)
事实证明,在调用run-or-load
时我必须使用不同的语法,这允许lambda像闭包一样:
(defmacro run-or-load-f (mode func)
`(lambda()
(interactive)
(run-or-load ,mode ,func)))