2016-03-07 54 views
1

我试图附加一个密钥处理函数,以便首次执行一个包装函数,该函数检查库是否已被加载,如果没有,则在最终执行预期函数之前加载它。将变量暴露给从defun中返回的lambda

的想法是能够做到:

(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))) 

我遇到的问题是,我不知道如何公开modefunc以上的拉姆达。我甚至不确定我需要一个宏,但它似乎确实如此。

完成的缘故,上面的功能run-or-load很干脆:

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

回答

3

不,你的回答是不是允许lambda表现得像封闭”。

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

你用逗号代替backquote的答案是替代这些变量的值代替lambda中的变量。也就是说,它删除了这些自由变量,将它们替换为构建(评估)lambda时的值

在这里使用闭包的好处是当调用函数(不只是当它被定义时)时,变量可用。 (如果你并不需要当时的变量,那么这个优势消失。)

如果您用过的defun代替defmacro然后关闭的另一个优点是,所产生的功能可以自动在文件字节编译被编译。

相反,使用反向引用的lambda方法,字节编译时的结果只是一个列表:(lambda ...)。编译器无法知道您打算始终将该列表用作函数,因此它不会编译到函数中 - 每次调用该函数时都会将其评估为列表。 (除非你明确地调用字节编译器来编译它。)

+0

优秀的答案。谢谢! – miguelg

1

原来我不得不使用不同的语法调用run-or-load,允许lambda来像一个封闭时:

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