Emacs 24爲本地變量添加了可選的詞彙綁定。我想在我的模塊中使用這個功能,同時保持與XEmacs和以前的Emacs版本的兼容性。Emacs中的詞彙範圍:與舊版Emacsen兼容
在Emacs 24之前,獲取閉包的最簡單方法是使用cl-macs
中定義的lexical-let
表單,該表單用一些聰明的宏觀欺騙來模擬詞法範圍。雖然這elisp的程序員之間從來沒有非常受歡迎,它的工作,創造真正的和有效的封鎖,只要你記得包起來lexical-let
,在這個僞代碼:
(defun foo-open-tag (tag data)
"Maybe open TAG and return a function that closes it."
... do the work here, initializing state ...
;; return a closure that explicitly captures internal state
(lexical-let ((var1 var1) (var2 var2) ...)
(lambda()
... use the captured vars without exposing them to the caller ...
)))
的問題是:什麼是使用新詞法綁定的最佳方式,同時保留對Emacs 23和XEmacs的支持?目前,我解決它通過定義擴展特定包宏進lexical-let
或入尋常let
取決於lexical-binding
是否綁定和真實:
(defmacro foo-lexlet (&rest letforms)
(if (and (boundp 'lexical-binding)
lexical-binding)
`(let ,@letforms)
`(lexical-let ,@letforms)))
(put 'foo-lexlet 'lisp-indent-function 1)
... at the end of file, turn on lexical binding if available:
;; Local Variables:
;; lexical-binding: t
;; End:
此解決方案,但由於新的特殊形式爲非感覺笨重 - 標準,沒有正確突出顯示,不能在edebug
下進入,並且通常會引起注意。有沒有更好的辦法?
編輯思想
兩個例子更聰明(不一定好)解決方案,允許代碼繼續使用標準的形式來創建關閉:
使用的意見或編譯器宏使
lexical-let
擴展到let
在lexical-bindings
下,如果lexical-let
只分配到無論如何詞法範圍的符號。這個建議只會在foo.el
的字節編譯過程中暫時激活,因此其餘的Emacs的lexical-let
的含義保持不變。使用宏/代碼行走工具將
let
的未加前綴的符號編譯爲lexical-let
在舊的Emacsen下。這將僅適用於foo.el
的字節編譯期間。
如果這些想法有過度工程的味道,請不要驚慌:我不是建議按原樣使用它們。我對上述宏的替代品感興趣,其中該包得到更好的便攜式使用對於加載/編譯的一些額外複雜性的代價的收益。
EDIT 2
由於沒有一個已加強了一個解決方案,將允許模塊使用let
或lexical-let
保持不破壞他們的Emacs的休息,我接受Stefan的回答,其中指出以上宏是這樣做的方法。除此之外,通過使用bound-and-true-p
併爲edebug和lisp-indent添加一個優雅的聲明,我的代碼的答案得到了改善。
如果有人對此兼容性層提供了替代方案,或者優雅地實現了上述想法,我鼓勵他們回答。
如果我在通用lisp中編寫這個宏包裝,我可能會在這裏使用相同的基本方法。除了通過在頂層有一個defmacro bla-lexlet,然後有一個編譯時if結構來確定將代碼擴展到哪種形式(let或lexical),在這種情況下)。我不會把這作爲答案,因爲它是一種常見的口頭禪方式,也是你使用的基本方法。 –
好點,我現在修改了這個例子,將'if'移至宏展開時間。然而,這個問題中指出的反對'foo-lexlet'的論據依然存在。 – user4815162342