2

test.lisp:

(defvar test
  #'(lambda (var1)
      #'(lambda (var2)
          `((var1 . ,var1)
            (var2 . ,var2)))))
(defvar var1 'wrong)
(defvar var2 'wrong)

そしてREPLで:

$ clisp -q -i test.lisp
;; Loading file test.lisp ...
;; Loaded file test.lisp
[1]> (funcall (funcall test 'right) 'right)
((VAR1 . WRONG) (VAR2 . RIGHT))

Common Lisp は最近では字句的にスコープされるはずだと思っていたのに、 の値がvar1の内部ラムダによってキャプチャされないのはなぜtestですか? キャプチャされていることを確認するにはどうすればよいですか?

4

2 に答える 2

4

これは、インタープリターを使用すると表示されます。

最初にコンパイラを見てみましょう:

? (load "/tmp/test.lisp")
#P"/private/tmp/test.lisp"
? (funcall (funcall test 'right) 'right)
((VAR1 . RIGHT) (VAR2 . RIGHT))

まず、関数がコンパイルされます。コンパイラは字句バインディングを想定しています。次に、変数とを特別なものとしてDEFVAR宣言します(-> レキシカルではありません)。実行されたコードでは、コードはまだ字句バインディングを使用しています。VAR1VAR2

あなたは通訳を使用していました:

最初に関数がロードされます。何もコンパイルされません。次にandを特別なものとしてDEFVAR宣言します。VAR1VAR2

実行されたコードでは、インタープリターは動的バインディングを使用しています-宣言したように。インタープリターは実行時に変数を見て、それらが特別であると宣言されていることを確認します。

違い:

コンパイラは、特別な宣言の前にマシン コードを生成しました。したがって、実行時に字句バインディングを使用します。

インタープリターは実行時に既存の宣言を調べます。

スタイル

動的バインディングを避けたい場合は、変数を特別なものとして宣言しないでください。

于 2015-04-10T21:23:16.180 に答える
3

defvar(およびdefparameter) 変数が特別 (動的) であることを宣言します。*earmuffs*バインディングがレキシカルなのか動的なのかについての驚きを防ぐために、特別な変数を指定してください。

于 2015-04-10T21:14:56.880 に答える