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のサポートを維持しながら、新しいレキシカルバインディングを使用する最も良い方法は?
(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:
このソリューションは動作しますが、新しい特別なフォームが非であるため、それは不格好な感じ:現在、私はバウンドし、真であるかどうかlexical-binding
に応じてlexical-let
に、または通常のlet
に展開パッケージ固有のマクロを定義することによってそれを解決しました正常に強調表示されず、edebug
の下に入ることができず、一般に注意を引く。より良い方法がありますか?コードはクロージャを作成するための標準的なフォームを引き続き使用することができ、よりスマートな(必ずしも良くない)ソリューションのためのアイデアの
EDIT
二つの例:
助言を使用しますか、
lexical-let
をに展開するコンパイラマクロは、lexical-let
が字句スコープのシンボルにのみ割り当てられる場合、lexical-bindings
の下にlet
に展開されます。このアドバイスは、foo.el
のバイトコンパイル時にのみ一時的に有効になるため、lexical-let
という意味は残りのEmacsでは変更されません。マクロ/コードウォーカー機能を使用して、接頭辞のないシンボルの
let
を、古いEmacsenでlexical-let
にコンパイルします。これは、バイト・コンパイル中にfoo.el
の場合にのみ適用されます。
これらのアイデアが強烈なにおいをするのであれば驚かないでください。私はそれらをそのまま使用することを提案していません。私は上記のマクロの代替案に興味があります。このパッケージでは、読み込み/コンパイルの複雑さのために、より良い移植性の利点が得られます。usage
誰モジュールはEmacsの残りのためにそれらを壊すことなくlet
またはlexical-let
を使用して維持することが可能になる溶液でステップアップしなかったようEDIT 2
は、私はステファンの答えを受け入れています、上記のマクロはです。それに加えて、答えはbound-and-true-p
を使用し、edebugとlisp-indentのためのエレガントな宣言を追加することで、私のコードで改善されています。
誰かがこの互換性レイヤーの代わりに、または上のアイデアを上手く実装している場合は、その人に回答することをおすすめします。
私がこのマクロラッパーを共通のlispで書いていたのであれば、おそらく同じ基本的なアプローチを使用しています。それ以外の場合は、トップレベルで単一のdefmacro bla-lexletを持つことで評価を拒否し、コードを展開するフォームを決定する構文をコンパイルする(この場合letまたはlexical-let )。私は答えとしてこれを書いているわけではありません。それは一般的なリプスのアプローチであり、あなたが使ったのと同じ基本的なアプローチです。 –
良い点は、 'exp'をマクロ展開時間に移動する例を改訂しました。しかし、「foo-lexlet」に対する議論は依然として問題であると指摘した。 – user4815162342