1

私はEmacsの字句スコープ(Emacs 24の新機能)間の相互作用を実験してadd-to-listいて、相互作用が混乱していることに気づき、それを理解する方法がわかりません。setの代わりに使用することを除いて、これは最小限の例ですadd-to-list。(通常、引用符で囲まれた変数名を使用するという点でset似ています)add-to-list

(eval
 '(progn
    (setq a "global")
    (let ((a "apple"))
      (defun my-print-a ()
        (print a)
        (set 'a "by set")
        (print a))
      (setq a "mature apple"))
    (let ((a "banana"))
      (my-print-a))
    (print a))
 t) ;; t for lexical scoping

上記のコードは、「mature apple」、「mature apple」、「byset」を順番に出力します。最初の印刷結果である「成熟したリンゴ」は、字句スコープ(字句クロージャをサポート)で期待どおりであり、ここで驚くことはありません。しかし、2番目と3番目の印刷の結果は私には驚くべきものです。これ(set 'a "by set")は、名前のグローバルバインディングを認識して影響を与えるだけであるかのようですa

これは意図された動作ですか?それともこれはバグですか?意図されている場合、この動作をどのように理解しますか?

set字句スコープがオンになっている限り、影響を与えるのは常にグローバルバインディングであると想定するのは正しいですか?

を使用(eval '(progn ...) nil)すると、動的スコープで期待どおりに動作し、の動作はその場合(set 'a ...)と同じになり(setq a ...)ます。字句スコープと引用符で囲まれた変数を一緒に使用する場合にのみ、この落とし穴が表示されます。


アップデート:

マニュアルによると、意図した動作のようです。ボイド変数については、マニュアルによると

字句バインディングルールでは、値セルは変数のグローバル値、つまり字句バインディング構造の外側の値のみを保持します。変数が字句的にバインドされている場合、ローカル値は字句環境によって決定されます。シンボルの値セルが割り当てられていない場合、変数はローカル値を持つ可能性があります。

字句バインディングについて

symbol-value、boundp、setなどの関数は、変数の動的バインディング(つまり、シンボルの値セルの内容)のみを取得または変更します。

symbol-value、boundp、setは、通常、引用符で囲まれた変数名((symbol-value 'var) (boundp 'var) (set 'var 123))で呼び出される関数です。これらの関数は、シンボルの値セルのみを取得または設定し、字句バインディングルールでは、値セルはグローバル値のみを保持します。したがって、字句バインディングでは、引用符で囲まれた変数を使用すると、グローバル値のみが取得または設定されます(変数が特別な変数でない場合)。結果が字句(リンゴ)でも動的(バナナ)でもないという点でまだ奇妙に思えますが。

4

1 に答える 1

1

コードは、Emacsが字句スコープ対応プログラムの記述を期待する方法で記述されていません。

http://www.gnu.org/software/emacs/manual/html_node/elisp/Definitions.html

defvarおよびdefconstは、シンボルをグローバル変数(Lispプログラムの任意の時点でアクセスできる変数)として定義する特殊な形式です。

(...)

setq原則として、最初に変数として定義されているかどうかに関係なく、。を使用して任意のシンボルに変数値を割り当てることができます。ただし、使用するグローバル変数ごとに変数定義を作成する必要があります。そうしないと、字句スコープを有効にして評価した場合、Lispプログラムが正しく動作しない可能性があります。

http://www.gnu.org/software/emacs/manual/html_node/elisp/Lexical-Binding.html

symbol-value、、のような関数はboundpset変数の動的バインディング(つまり、シンボルの値セルの内容)のみを取得または変更することに注意してください。また、defunまたはの本体のコードは、defmacro周囲の字句変数を参照できません。

http://www.gnu.org/software/emacs/manual/html_node/elisp/Setting-Variables.html

特殊形式:setq[記号 形式]..。

この特殊な形式は、変数の値を変更する最も一般的な方法です。(...)シンボルの現在のバインディングが変更されます。

(...)

機能:set シンボル

この関数は、シンボルの値セルにを入れます。

(...)

動的変数バインディングが有効な場合(デフォルト)、シンボル引数を評価するのに対し、評価しないという事実を除けば、setと同じ効果があります。ただし、変数が字句的にバインドされている場合、その動的値に影響を与えますが、現在の(字句)値に影響を与えます。setqsetsetqsetsetq

それをグローバル変数としてdefvar定義すると、マニュアルで説明されているように、関数内のaすべての参照が動的にバインドされていることがわかります。amy-print-a

(eval
 '(progn
    (defvar a nil)
    (setq a "global")
    (let ((a "apple"))
      (defun my-print-a ()
        (print a)                       ; "banana"
        (set 'a "by set")              
        (print a))                      ; "by set"
      (setq a "mature apple"))
    (let ((a "banana"))
      (my-print-a))
    (print a))                          ; "global"
 t)
于 2012-08-18T16:54:37.797 に答える