それで、私はLispで
setq と defvar を読みました
。
特に setf と defvar の違いについて。そこで、このアイデアを少しいじってみることにしました。
CL-USER> (defun foo ()
(setf x 10)
(print x))
; in: DEFUN FOO
; (SETF X 10)
; ==>
; (SETQ X 10)
;
; caught WARNING:
; undefined variable: X
;
; compilation unit finished
; Undefined variable:
; X
; caught 1 WARNING condition
FOO
CL-USER> x
; Evaluation aborted on #<UNBOUND-VARIABLE X {10040F1543}>.
CL-USER> (foo)
10
10
CL-USER> x
10
さて、setf を使用して既存の変数の値を変更する必要があることはわかっていますが、未定義の変数の警告は SBCL でかなりうまく処理されているようです (ただし、異なる CL 実装ではこれを異なる方法で処理する可能性があることを読みましたが、そうではありません)。するのが最善です)。
2 番目のテストに入ります。
CL-USER> (defun bar ()
(defvar y 15)
(print y))
; in: DEFUN BAR
; (PRINT Y)
;
; caught WARNING:
; undefined variable: Y
;
; compilation unit finished
; Undefined variable:
; Y
; caught 1 WARNING condition
BAR
CL-USER> y
; Evaluation aborted on #<UNBOUND-VARIABLE Y {10045033D3}>.
CL-USER> (bar)
15
15
CL-USER> y
15
リンクに従って、 setf を defvar に変更しました。これにより、変数を一度に作成してバインドする必要があると思います。ここで、未定義の変数の警告が (print y) 行にプッシュされます...ここで何が起こっているのでしょうか?
二次的な質問として、関数内で割り当てられた変数の値は、Python の場合のように、関数の外ではアクセスできないと予想しています。
>>> def foo():
... x = 10
... print x
...
>>> foo()
10
>>> x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
これは、一般的な Lisp がスコープを処理する方法、つまり defvar が「グローバルな特殊な変数」を作成する方法と関係があると推測しています...だから最後にもう一度試してみました (let ...)
CL-USER> (defun baz () (let ((z 10)) (print z)) (incf z 10) (print z))
; in: DEFUN BAZ
; (INCF Z 10)
; --> LET*
; ==>
; (SETQ Z #:NEW0)
;
; caught WARNING:
; undefined variable: Z
;
; compilation unit finished
; Undefined variable:
; Z
; caught 1 WARNING condition
そして、defvar、defparameter、setf、および setq の違いを読んだ後、これは正しく機能するようです:
CL-USER> (defun apple ()
(defparameter x 10)
(print 10))
APPLE
CL-USER> x
; Evaluation aborted on #<UNBOUND-VARIABLE X {1004436993}>.
CL-USER> (apple)
10
10
CL-USER> x
10
私の質問を繰り返します: 1) setf、defvar、および let で実際に何が起こっているのですか?
2) Python の例のように、一般的な Lisp で関数内の変数のスコープを取得する方法はありますか?