12

編集:同じ質問をする簡単なバージョンを思いついたので、最初の答えの後にサンプルコードを変更しました。

私は現在、CommonLispのスコープ特性を学んでいます。しっかりと理解したと思った後、結果を予測できるいくつかの例をコーディングすることにしましたが、明らかに間違っていました。私は3つの質問があり、それぞれが以下の例に関連しています。

例1:

(defmethod fun1 (x)
  (print x)
  (fun2))

(defmethod fun2 ()
  (print x))

(fun1 5)

出力:

5 
*** - EVAL: variable X has no value

質問:これは理にかなっています。xは静的スコープであり、fun2には、xの値を明示的に渡さずに見つける方法がありません。

例2:

(defvar x 100)

(defmethod fun1 (x)
  (print x)
  (fun2))

(defmethod fun2 ()
  (print x))

(fun1 5)

出力:

5
5

質問:xが100の値ではなく、fun1が与えた値でfun2に突然表示される理由がわかりません...

例3:

(setf x 100)

(defmethod fun1 (x)
  (print x)
  (fun2))

(defmethod fun2 ()
  (print x))

(fun1 5)

出力:

5
100

質問:宣言されていない変数でsetfを呼び出すことは明らかに未定義なので、これらの結果を無視する必要がありますか?これは、2番目の例で期待することです...

任意の洞察をいただければ幸いです...

4

1 に答える 1

23

を使用して未定義の変数を設定する効果はsetf、ANSI Common Lisp では定義されていません。

defvar特別な変数を定義します。letこの宣言はグローバルであり、バインディングにも影響します。これが、慣例によりこれらの変数が と書かれている理由です*foo*。で定義xしたことがある場合defvar、それは特別であると宣言され、後で字句的に宣言する方法はありません。

letデフォルトでは、ローカルのレキシカル変数を提供します。変数がすでに特別であると宣言されている場合 (たとえば、 が原因defvar)、新しいローカル動的バインディングが作成されるだけです。

アップデート

  • 例 1。

見るものは何もありません。

  • 例 2

x特別宣言されました。変数のすべての使用で、x動的バインディングが使用されるようになりました。関数を呼び出すときは、 にバインドx5ます。動的に。他の関数は、この動的バインディングにアクセスしてその値を取得できるようになりました。

  • 例 3

これは、Common Lisp では未定義の動作です。宣言されていない変数を設定しています。次に何が起こるかは、実装に依存します。あなたの実装(ほとんどは似たようなことをします)は、シンボル値xto に設定し100ます。ではfun1x字句的にバインドされています。fun2評価ではx、 のシンボル値 (または動的にバインドされた値) を取得しますx

何か他のことをした (する?) 実装の例として: CMUCL 実装はx、例 3 でデフォルトで特別であることも宣言します。未定義の変数を設定すると、それが特別であると宣言されます。

ノート

ポータブル標準に準拠した Common Lisp コードでは、グローバル変数は と で定義されdefvarますdefparameter。どちらも、これらの変数を特別なものとして宣言しています。これらの変数のすべての使用には、動的バインディングが含まれるようになりました。

覚えて:

((lambda (x)
   (sin x))
 10)

基本的に同じです

(let ((x 10))
  (sin x))

これは、バインディング内letの変数バインディングと関数呼び出し内の変数バインディングが同じように機能することを意味します。以前にどこかで特別に宣言されていた場合x、どちらも動的バインディングを伴います。

これは、Common Lisp 標準で指定されています。たとえば、SPECIAL 宣言の説明を参照してください。

于 2011-10-17T01:18:30.307 に答える