2012-09-17 14 views
13

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のためのエレガントな宣言を追加することで、私のコードで改善されています。

誰かがこの互換性レイヤーの代わりに、または上のアイデアを上手く実装している場合は、その人に回答することをおすすめします。

+0

私がこのマクロラッパーを共通のlispで書いていたのであれば、おそらく同じ基本的なアプローチを使用しています。それ以外の場合は、トップレベルで単一のdefmacro bla-lexletを持つことで評価を拒否し、コードを展開するフォームを決定する構文をコンパイルする(この場合letまたはlexical-let )。私は答えとしてこれを書いているわけではありません。それは一般的なリプスのアプローチであり、あなたが使ったのと同じ基本的なアプローチです。 –

+0

良い点は、 'exp'をマクロ展開時間に移動する例を改訂しました。しかし、「foo-lexlet」に対する議論は依然として問題であると指摘した。 – user4815162342

答えて

6

letはvarがdefvar D」であったか否かに応じて動的結合または結合語彙のいずれかを使用し、一方、より具体的lexical-letは常に、語彙的結合を使用します)あなたのアプローチは、それが得られるほど良いと思います。あなたはdeclareに依存したくない場合は、(put 'foo-lexlet 'edebug-form-spec 'let)を使用することができ、

(defmacro foo-lexlet (&rest letforms) 
    (declare (indent 1) (debug let)) 
    (if (bound-and-true-p lexical-binding) 
     `(let ,@letforms) 
    `(lexical-let ,@letforms))) 

:あなたは簡単にカントー、それにEdebugのステップを行うことができます。

+0

'declare'のチップをありがとう、私はそれを使用します。あなたの答えを受け入れるのをやや長く延期し、代わりのアイデアを奨励します。これを簡単にするために、私はそのような解決策が取るべき方向の例を追加するために質問を編集しました。 – user4815162342

2

defadviceをフックするのにlexical-letを使用することが1つの解決策です。私は以下のアドバイスを書いた。それはうまくいくようだ。これはbyte-compileも認識しています。 lexical-let及び字句結合のlet全く同じことをしないので

(defadvice lexical-let (around use-let-if-possible (bindings &rest body) activate) 
    (if (and (>= emacs-major-version 24) 
      (boundp 'lexical-binding) 
      lexical-binding) 
     (setq ad-return-value `(let ,bindings . ,body)) 
    ad-do-it)) 
+0

あなたの '.emacs'でこのアドバイスをユーザとして使用しているのですか、パッケージ内のサードパーティのパッケージ作成者ですか?このアドバイスを有効にしても、ユーザーの背中の背後のどこでも 'lexical-let 'の振る舞いは変わらないことは私には明らかではありません。 – user4815162342

-1

字句-letが、letのと同じ引数リストのフォーマットを持つことになりますので、どのようなものについて:このシムは、新しいEmacsは古いコードの字句-せた部分を読み取ることができるようにする必要があり

(if (older-emacs-p) 
    (setf (macro-function 'let) (macro-function 'lexical-let)) 
    (setf (macro-function 'lexical-let) (macro-function 'let))) 

だけでなく、もう一方の方法(古いEmacsに新しいコードの部分を読み込ませる)を許可します。

これはCommon Lispです。誰かがEmacsにそれを翻訳する気に?

lexical-let/letが特別な形式(マクロではない)として実装されていると、問題が発生することがあります。

また、letが古いEmacsで定義されていれば、これは完全互換のケースを完全に破る可能性があります。それは...ですか? (私はEmacsについてほとんど知っていません;私が選んだエディタではありません)。しかし、下位互換性のあるケースは、それに関係なくより重要になる可能性があります。

+0

2番目の 'setf'は冗長であるようです - ' let'と 'lexical-let'のマクロ関数を交換するために単一の' psetf'を使うことを意味しましたか?これは、1つのパッケージをコンパイルするために、残りのEmacsセッションで 'let'の意味を変更するように見えます。ユーザーに警告することなくそれをしたモジュールは、大きく壊れていました。 – user4815162342

関連する問題