2016-03-07 64 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)))