3

宣言SPECIAL、特殊演算子LET、マクロDEFVAR、および Common Lisp における動的スコープとレキシカル スコープに関する StackOverflow のいくつかの質問 (たとえば、 this ) に関するドキュメントを読んだ後でも、次の動作が理解できません。これらのフォームを SBCL で評価します。

;; x is a free variable
CL-USER> (defun fn ()
           (print x))
; in: DEFUN FN
;     (PRINT X)
; 
; caught WARNING:
;   undefined variable: X
; 
; compilation unit finished
;   Undefined variable:
;     X
;   caught 1 WARNING condition
FN

CL-USER> (describe 'x)
COMMON-LISP-USER::X
  [symbol]
; No value

CL-USER> (let ((x 'dinamic_1st_binding))
           (declare (special x))
           (print x)
           (fn)
           (let ((x 'dinamic_2nd_binding))
             (declare (special x))
             (print x)
             (fn))
           (let ((x 'lexical_1st_binding))
             (print x)
             (fn))
           (values))

DINAMIC_1ST_BINDING 
DINAMIC_1ST_BINDING 
DINAMIC_2ND_BINDING 
DINAMIC_2ND_BINDING 
LEXICAL_1ST_BINDING 
DINAMIC_1ST_BINDING 
; No value

;; x is defvar'ed as a top level form
CL-USER> (defvar x 'dinamic_global_binding)
X

CL-USER> (describe 'x)
COMMON-LISP-USER::X
  [symbol]

X names a special variable:
  Value: DINAMIC_GLOBAL_BINDING
; No value

CL-USER> (let ((x 'dinamic_1st_binding))
           (declare (special x))
           (print x)
           (fn)
           (let ((x 'dinamic_2nd_binding))
             (declare (special x))
             (print x)
             (fn))
           (let ((x 'lexical_1st_binding))
             (print x)
             (fn))
           (values))

DINAMIC_1ST_BINDING 
DINAMIC_1ST_BINDING 
DINAMIC_2ND_BINDING 
DINAMIC_2ND_BINDING 
LEXICAL_1ST_BINDING 
LEXICAL_1ST_BINDING 
; No value

変数が defvarさfnれる前にへの 3 番目の呼び出しが出力され、変数が defvar された後に出力されるのはなぜですか?xDINAMIC_1ST_BINDINGxLEXICAL_1ST_BINDING

4

3 に答える 3

6

一歩一歩進みましょう。

フォーム1

(defun fn ()
  (print x))

これは を定義しますfn

参照されたx変数は字句的に宣言されていないため、警告が表示されます。

フリー参照変数は通常、フリー宣言でローカルに想定されます1。これは標準では定義されていませんが、ほとんどの実装では定義されており、警告が通知されます。special

(setq x ...)同じ原則が、ファイルまたは REPLのトップレベル フォームの評価にも適用されます。

これらの状況はいずれも、としてグローバルに宣言することは想定されていません。xspecial

フォーム2

(describe 'x)

xは単なる記号です。世界的には何も起こりませんでした。

フォーム3

(let ((x 'dinamic_1st_binding))
  (declare (special x))
  (print x)
  (fn)
  (let ((x 'dinamic_2nd_binding))
    (declare (special x))
    (print x)
    (fn))
  (let ((x 'lexical_1st_binding))
    (print x)
    (fn))
  (values))

への最初のバインディングxは、ローカルに宣言されていspecialます。ということで、fn取り上げます。

への 2 番目のビンジングは、 への呼び出し後に巻き戻さxれる の新しい動的バインディングを作成するだけで、ほぼ同じです。xfn

3 番目のバインディングはレキシカル バインディングです。これは、バインドされた変数のグローバル宣言またはローカルバインド宣言xがない限り、すべてのバインディングがレキシカルであるためです。 special special

したがって、fnの最新の動的バインディングを取得する はx、 を取得しdinamic_1st_bindingます。

フォーム内のxs は、 のprint囲んでいる意味を使用するため、それが特別であると宣言されている場合xは を選択し、そうでない場合special xは字句を選択xします。

フォーム 4

(defvar x 'dinamic_global_binding)

これはグローバルにxasを宣言しspecial、それを に設定symbol-valuedinamic_global_bindingます。

シンボルxを変数として使用するたびに、このグローバル special宣言で汚染されます。xこの時点から、レキシカル変数として名前が付けられた変数をコードがバインドまたは参照する標準的な方法はありません。

フォーム5

(describe 'x)

ここで、前の形式の副作用を観察します。xグローバルに特殊で、現在の動的値はdinamic_global_bindingです。

フォーム6

(let ((x 'dinamic_1st_binding))
  (declare (special x))
  (print x)
  (fn)
  (let ((x 'dinamic_2nd_binding))
    (declare (special x))
    (print x)
    (fn))
  (let ((x 'lexical_1st_binding))
    (print x)
    (fn))
  (values))

のバインディングはすべてx特別です。∎<br/>



  1. 宣言は、バインディングを実行する形式でバインディングの確立に意味を与える場合にバインドされ、それ以外の場合、つまりバインディングの参照/使用にのみ意味を与える場合は自由です

したがって、次の例:

(defun fn2 ()
  (print y))

(let ((y 1))
  (fn2)
  (locally (declare (special y))
    (fn2)))

動的にletバインドしません。自由な宣言を通じて動的変数として扱うように参照するyコードをレキシカルに作成するだけです。この場合、両方の呼び出しでエラーが通知されます。locallyyfn2

以下:

(let ((y 1))
  (declare (special y))
  (print y)
  (let ((y 2))
    (print y)
    (locally (declare (special y))
      (print y))
    (print y)))

印刷されます:

1
2
1
2

の最初のバインディングにyバインドされ specialた宣言があるため、動的バインディングです。

の 2 番目のバインディングにyバインドされた special宣言がなく、 globalyではないため、レキシカル バインディングです。 special

したがって、 へのアクセスyは、 に関する (欠落している) 宣言によっても条件付けられyます。

2 番目の宣言は自由宣言であり、変数への参照はy動的として扱われます。したがって、named 変数への直前のバインドは、このfree宣言yによって変更されません。

次の例:

(let ((y 1))
  (print y)
  (locally (declare (special y))
    (print y)))

printは 2 番目の形式では失敗します。これは、 への参照yが動的であり、 に対する動的バインディングが確立されていないためですy。つまり、yはバインドされておらず、unbound-variableエラーが通知されます。

于 2013-07-31T16:02:03.153 に答える
2

1 つのケースでは、x の字句バインディングがあります。

2 の場合、字句バインディングはありません。シンボルを持っているだけですが、最後の x も動的にバインドされていることが明確に示されているため、誤解を招く可能性があります。

于 2013-07-28T03:24:12.690 に答える
2

Defvar ら。変数がグローバルに特別であると宣言します。つまり、special宣言を省略しても、この変数のすべてのバインディングは動的です。

2回目の実行では、とにかく動的バインディングであるため、バインディングは誤解を招きますx'lexical-1st-binding

于 2013-07-29T13:25:43.547 に答える