2017-05-23 8 views
2

や他の言葉で:??それは(シンボル)の一部ではないとCLでの変数は可能ですは中Xです(((X ...)完全に具体化シンボルをLET

私は思います私はCLでの変数についての深遠な誤解を有することができる。

私は常にCLは一切の変数、記号のみ、およびシンボルは(他の特性の中で)持っている名前と(変数)値のセルを持っていないと思った。
と誰かが言ったとき"変数xは値が" "と短いと思った" xというシンボルの値のセル値は42 "です。

これはおそらく間違っています。

Iは

> (let ((a 42)) 
     (type-of 'a)) 
SYMBOL 
; caught STYLE-WARNING: 
; The variable A is defined but never used. 

を入力この例では、字句変数aその値はセル42に設定されている完全に具体化シンボルでありますか?

警告The variable A is defined but never usedはそうでないことを示唆しており、字句変数はシンボルaと同じではないと思われます。(type-of 'a)

答えて

5

Common Lispは2つの評価のために特別な意味を持つデータ型があります。

  • コンスセルを/リスト - Lispのソースコードで使用される>、リストはLispのフォーム
  • シンボルがあります - >さまざまな目的のための名前として使用される

Lispコードのデータとして使用する場合は、それらをテイ。

どちらもLispソースコードで使用されますが、コードをコンパイルすると消滅することがあります。

変数は、ソースコードのシンボルとして書き込まれます。しかし、コンパイルされたコードでは、の語彙変数であるときに、それらは消え去ることがあります。SBCLを使用して

例:

(defun test (foo) 
    (+ foo foo)) 

ファイル今、私たちが行う:

CL-USER> (proclaim '(optimize (debug 0))) ; the compiler saves no debug info 
; No value 
CL-USER> (compile-file "/tmp/test.lisp") 
; compiling file "/private/tmp/test.lisp" (written 23 MAY 2017 09:06:51 PM): 
; compiling (DEFUN TEST ...) 

; /tmp/test.fasl written 
; compilation finished in 0:00:00.013 
#P"/private/tmp/test.fasl" 
NIL 
NIL 
CL-USER> (find-symbol "FOO") 
FOO 
:INTERNAL 

をコンパイラは、ソースコードを読んで、コンパイルFASLファイルを作成しました。シンボルFOOが現在のパッケージに含まれていることがわかります。 FOOは、ソースコードの変数に名前を付けます。

これでSBCLを終了し、再起動します。

はのは、マシンコードをロードしてみましょう:

CL-USER> (load "/tmp/test") 
T 
CL-USER> (find-symbol "FOO") 
NIL 
NIL 

無記号FOOはもうありません。また、変数FOOの語彙値をシンボルFOOを使用して取得することもできません。シンボルからレキシカル値へのマッピング(明示的なレキシカル環境のようなもの)はありません。

4

値セルは、字句変数ではなく動的(AKA「特別」)変数に使用されます。字句変数はソースコード内のシンボルですが、シンボルとの実行時関係はありません(デバッガによる内部使用を除く)。

あなたが書いたのであれば:

(let ((a 42)) 
    (declare (special a)) 
    (print (symbol-value 'a))) 

を宣言はそれ動的変数になり、その後、あなたは、関数セルの値にアクセスすることができますので、それが働くだろう。

+0

これは、 'defun'、' lambda'、 'let'などで作成された字句変数がシンボルであるように見えるが、一度コンパイルされると、実際にはそうではないことを意味するのだろうか? – Frank

+1

これは、関数呼び出しがソースコードのリストと同じように、単にソースコードのシンボルです。それらがコンパイルされると、すべて機械コードに変わり、レキシカル変数はスタック位置にすぎません。 – Barmar

2

あなたがバインドされた変数aまたはその値の型が、あなたのlet形で変数と同じ名前を持つことを起こるリテラル定数記号のことを確認されていません。確認するには

(let ((a 42)) 
    (type-of 'literal-symbol)) 
; ==> symbol (since 'literal-symbol evaluates to a symbol, just like 'a does) 

をリテラル引用せずにそれを行う結合aの値の種類:ここ

(let ((a 42)) 
    (type-of a)) 
; ==> (integer 0 281474976710655) 

あなたが実際にLETバインド値の型をチェックし、それは整数です。驚いたのは、42は数字ではなくシンボルですか?

(let ((a 10) (b 'a)) 
    (list a b)) 
; ==> (10 a) 

変数a'a引用符付きリテラルは同じではありません。表示されると同じように見えますが、'aはデータ、aはコードです。 CLでは、コンパイラはリストやシンボルを内部的に使用することがありますが、その実行が実装に完全に依存している場合や、実装可能なときにスタックを割り当てるほとんどの実装では、スタック割り当て変数を評価するコードは、スタックからのインデックスの値。 CLにはdisassembleという関数があり、SBCLの出力を何かからチェックすると、元のlispソースよりもCコンパイラの出力に似ています。

+0

は本当に面白いです!ありがとうございました – Frank

関連する問題