6

Lisp で動的/グローバル バインディングを作成する場合は、defparameter または defvar を使用します。また、defun 引数リストまたは let ステートメントを使用して、レキシカル バインディングをほとんどどこでも作成できることも知っています。

私が不思議に思っているのは、x が宣言されておらず、コード内の他の場所で使用されていない場合に、次のようなステートメントを作成するときに、正確に何を作成するかということです。

(setf x 10 )

これは正常に動作しているように見え、x はレキシカル変数のようには振る舞わないようです。defparameter または defvar を使用した場合と同じように、実際には動的グローバルですか、それともまったく別のものですか?

4

3 に答える 3

6

それが実際に行うことは、ANSI Common Lisp 標準では規定されていません。

一般に、動的にバインドされた値またはグローバル値を設定するだけの CL 実装を好みます。他に何もすべきではありません。デフォルトでは、CMUCL はシンボルを special と宣言するのが良い考えだと考えていたようです。しかし、グローバルな特殊宣言を取り除く明白な方法がなかったので、それは悪い考えでした。

したがって、通常は次のようなものを期待します (ここでは LispWorks):

CL-USER 66 > (defun foo () (setf x44 10))
FOO

グローバル変数はまだバインドされていません。

CL-USER 67 > x44

Error: The variable X44 is unbound.
  1 (continue) Try evaluating X44 again.
  2 Specify a value to use this time instead of evaluating X44.
  3 Specify a value to set X44 to.
  4 (abort) Return to level 0.
  5 Return to top loop level 0.

Type :b for backtrace or :c <option number> to proceed.
Type :bug-form "<subject>" for a bug report template or :? for other options.

CL-USER 68 : 1 > :top

関数を呼び出しましょう:

CL-USER 69 > (foo)
10

これでグローバルな値になりました:

CL-USER 70 > x44
10

ただし、変数は特別であると宣言されていません ( DEFVARorによるようにDEFPARAMETER)。ここで字句バインディングが確立されます。

CL-USER 71 > (let ((x44 20)) (foo) x44)
20

ローカル変数を特別なものとして宣言すると、関数はバインドを変更します。

CL-USER 72 > (let ((x44 20)) (declare (special x44)) (foo) x44)
10
于 2012-12-26T13:06:39.763 に答える
2

非常に手短に言えば、あなたが観察setqした の展開である は、何をするかsetf、何をするかの半分だけを行うと考えることができます:defvardefparameter

これを行うと考えてくださいdefparameter

(declaim (special x))
(setq x 10)

つまり、メタデータ (どのようなものかに関するデータx) をコンパイラに提供し (この場合、「特別な」変数であることを伝えます)、値を割り当てます。

特に、defvarトップレベルのフォームの場合、このようには動作しません。標準的な動作は、シンボルの値セルを 1 回だけ初期化することです。そのため、そのコードはさらに複雑になり、次のように考えることができます。

(unless (boundp x)    ; This is not entirely correct, because if the symbol
                      ; is otherwise known to the environment, but is unbound
                      ; defvar will not re-bind it, but I can't think of a way
                      ; to mimic that behavior
  (declaim (special x))
  (setq x 10))

コンパイラに提供されるメタデータは、コードの動作に影響を与える場合と与えない場合があります。一般に、メタデータは、コンパイラがコードの背後にある意図をより適切に判断するのに役立つため、最適化が行われる可能性があります。しかし、ドキュメントやデバッグにも役立ちます。

Hyperspecについてspecialdeclareで読むことができます。

于 2012-12-26T10:33:51.270 に答える
0

私の知る限り、宣言されていない変数でsetf(setqに展開)を使用しないでください。動作は実装によって異なる可能性があり、たとえ REPL のコードが正常に機能したとしても、コンパイルされたプログラムは予期しない場所でバグが発生する可能性があります。次のようなことをすると、clisp で警告が表示されます。

>(defun internal-setf () (setf some-var 10))
>(compile 'internal-setf)
WARNING: in INTERNAL-SETF : SOME-VAR is neither declared nor bound,
     it will be treated as if it were declared SPECIAL.
于 2012-12-26T10:38:20.660 に答える