6

次の emacs lisp ファイルは、アリスが init ファイルで字句的にバインドされたローカル変数を使用し、ボブが init ファイルでグローバルな特殊変数としてfoo定義し、アリスがボブの init ファイルコードの一部を彼女自身の init ファイルに借用した場合に何が起こるかを確認するためのものです。それが特別になることを知っています。foodefvarfoo

;; -*- lexical-binding: t; -*-
;; Alice init file

;; Alice defining alice-multiplier
(defun alice-multiplier-1 (foo)
  (lambda (n) (* n foo)))
(defun alice-multiplier-2 (num)
  (let ((foo num))
    (lambda (n) (* n foo))))

;; Alice using alice-multiplier
(print
 (list
  :R1 (mapcar (alice-multiplier-1 10) (list 1 2 3))
  :R2 (mapcar (alice-multiplier-2 10) (list 1 2 3))))

;; from Bob's code
;; ...    
(defvar foo 1000)
;; ...

;; Alice using alice-multiplier
(print
 (list
  :R3 (mapcar (alice-multiplier-1 10) (list 1 2 3))
  :R4 (mapcar (alice-multiplier-2 10) (list 1 2 3))))

出力:

(:R1 (10 20 30) :R2 (10 20 30))

(:R3 (10 20 30) :R4 (1000 2000 3000))

結果 R1 と R2 は、期待どおりです。結果 R4 は defvar のドキュメントと一致していますが、アリスがボブのコードを読まなければ驚くかもしれません。

  1. R3は意外だった。なぜR3はこうなった?

  2. R4といえば、アリスがfoo他人に特別にされないようにするにはどうすればいいですか? たとえば、foo彼女が init ファイルまたは emacs パッケージの 1 つで使用するレキシカル ローカル変数である(defvar foo "something")可能性があり、たまたま使用するパッケージの一部である可能性があるか、またはfoo将来のバージョンで導入される新しい特殊変数名の 1 つである可能性があります。 Emacsの。Alice が Emacs に「このファイルでは、外部からのコードが同じ名前の特殊変数を使用している場合でも、foo は常に字句的であるべきです」と言うファイルに入れることができるものはありますか?

4

2 に答える 2

4

何が起こっている

「理論的」(Scheme/Common Lisp) の観点から、レキシカル バインディングを有効にするとすぐに、すべての実用的な目的alice-multiplier-1同じalice-multiplier-2になります。それらの動作の違いは Emacs Lisp のバグであり、そのように報告する必要があります。

編集済み

コード (つまり、 2defun;; -*- lexical-binding: t; -*-行) をファイルに入れるemacs-list-byte-compile-and-loadと、次の 4 つの形式を評価することで私の主張をテストできます。

(disassemble 'alice-multiplier-1)
(disassemble 'alice-multiplier-2)
(disassemble (alice-multiplier-1 10))
(disassemble (alice-multiplier-2 10))

3 と 4 は同一で、1 と 2 は 1 つの命令が異なることがわかります (これはバグとして Emacs メンテナに報告する必要がありますが、動作には影響しません)。

逆アセンブリのどれも言及していないことに注意してください。fooつまり、はそれらの動作に影響しdefvarません。

すべてが良いです!

解釈された

実際、表示される動作は正しくありません。 の正しい結果defvar

(:R1 (10000 20000 30000) :R2 (10000 20000 30000))

これを emacs メンテナーに報告してください。

違う???

はい、解釈されたコードの動作に影響を与えますdefvar (そしてすべきです!)コンパイルされたコードの動作には影響しませ(そしてすべきではありません!) 。

あなたがすべきこと

「あなたの」記号の前fooに.specialalice-

ただし、定義を使用してファイルをバイトコンパイルするとalice-multiplier-1、コンパイルされたファイルには何も含まれないfooため、将来の の宣言はfoo影響しません。

于 2013-07-02T15:24:20.837 に答える
1

2 番目の質問については、私の知る限り、ありません。しかし、まだ回避できます。つまり、2 つの命名規則を採用することです。これを黄色と緑と呼びます。

黄色の命名規則

すべての特殊変数には黄色の名前が必要です。黄色の名前は、少なくとも 1 つのハイフンを含む名前です。たとえば、hello-worldga-na-daは黄色の名前です。公式の Emacs Lisp マニュアルとバイト コンパイラは、この規則を奨励しています。

グリーン命名規則

緑の名前は、黄色ではない名前です。たとえば、helloworldganadaは緑色の名前です。

すべてのレキシカル非ローカル/フリー変数には、緑色の名前が必要です。非ローカル変数とは 内の無名関数の本体には、 、、のalice-multiplier-23 つの名前が記載されています。これら 3 つのうち、(無名関数の) 関数本体内にのみ宣言があります。他の 2 つは、無名関数の観点からは非ローカルです。これらは非ローカル変数です。nfoonumn

Alice と Bob が 2 つの命名規則に固執している限り、すべて問題ありません。今はそうでなくても、次の段階を経て、最終的には相互にコミュニケーションすることさえなく、2 人がこれらの慣習に収束する可能性があります。

  1. Alice と Bob は、どの規則にも固執しません。

  2. マニュアルとバイトコンパイラは黄色の命名規則を奨励しているため、アリスとボブの両方が黄色の規則に固執し始める時期が来ます。

  3. アリスは、少なくとも他の人による黄色の特殊変数からコードを保護する緑色の規則を採用しています。

  4. Alice と Bob は、両方の規則に固執します。

衝突が発生する正確な条件については、特殊変数の侵入を参照してください。

于 2013-08-14T05:41:34.373 に答える