# 20240428122916 setf setq defvar defparameter の違い #common_lisp #tips 若干ややこしいく、前提となる知識が必要だが、 - defvar, defparameterはダイナミックスコープの変数(スペシャル変数)を定義する。 - letや未定義時のsetfはレキシカルスコープの変数を定義する。 グローバル変数をレキシカルに作る方法は(少なくとも標準的には)無い。 上記未定義時のsetfは期待した動作をするが、推奨されていない。 cf. - [[20240428125606 ダイナミックスコープ レキシカルスコープ |ダイナミックスコープ レキシカルスコープ]] - [lispguide.xml](https://google.github.io/styleguide/lispguide.xml?showone=Global_variables_and_constants#Global_variables_and_constants) Common Lisp does not have global lexical variables - defvar: 値が定義されていなければ定義する。上書きしようとしても存在している場合はできない(というか無視される)。 - defparameter: 定義されているかに関係なく定義する。すでに定義されていたら上書きする。 - defconstant: 定数を定義する。複数回定義しようとしたり、値を変更しようとするとエラーになる。 - setf: 定義された変数を変更するために使う。定義されていない変数を変更しようとすると、新規作成され、警告が出る。 - setq: 使わなくてよい。 setfはsetqの上位互換。 以下sbclをslimeで動かした時の、replでの実行結果 ```lisp ;; defvar (defvar b 100) ; 1回目 b; => 100 (defvar b 200) ; 2回目 b; => 100 ; とくにwarningなども出ず、シンプルに無視された (setf b 300) ; setfで変えられるの? b ; => 300 ; 変えらえる ;; defparameter (defparameter c 1) ; 1回目 c ; => 1 (defparameter c 2) ; 2回目 c ; => 2 ; 変わっている (setf c 3) ; setfで変えられるの? c; => 3 ; 変えられる ;; defconstant 定数を宣言 (defconstant d 1); 1回目 d ; => 1 (defconstant d 2); 2回目 エラー ;; The constant D is being redefined (from 1 to 2) ;; [Condition of type DEFCONSTANT-UNEQL] ;; See also: ;; Common Lisp Hyperspec, DEFCONSTANT [:macro] ;; SBCL Manual, Idiosyncrasies [:node] (setf d 3) ; setfしてみる これもエラー ;; Execution of a form compiled with errors. ;; Form: ;; (SETQ D 3) ;; Compile-time error: ;; D is a constant and thus can't be set. ;; [Condition of type SB-INT:COMPILED-PROGRAM-ERROR] ;; 定義されていない値をsetf (setf e 1) ; => warning ;; in: SETF E ;; (SETF E 1) ;; ;; caught WARNING: ;; undefined variable: COMMON-LISP-USER::E ;; ;; compilation unit finished ;; Undefined variable: ;; E ;; caught 1 WARNING condition (setf e 2); 2回目 ;; 同様のwarningが出る e ; => 2 ;; defconstant強い。letでも変えられない (let ((d 2))) ;; Execution of a form compiled with errors. ;; Form: ;; (LET ((D 2))) ;; Compile-time error: ;; COMMON-LISP-USER::D names a defined constant, and cannot be used in LET. ;; [Condition of type SB-INT:COMPILED-PROGRAM-ERROR] ;; こう書いた場合もグローバルにアクセスできる? ;; ダイナミックスコープならできるはず (defun nazo () (defvar nazo_value 10)) (nazo) nazo_value ; => 10 できた ``` ### その他 識別子に使用可能な文字は? [変数](https://wisdom.sakura.ne.jp/programming/lisp/clisp5.html) には、 >変数名には、アルファベット、数値、記号で構成される識別子を指定します。 Common Lisp の識別子は、アルファベットの大文字小文字を区別しません。 次の記号を使うこともできます。 > + - * / @ $ % ^ & _ = < > ~ . > > ただし +1 や -20 という表記は整数として認識できるため識別子にはなりません。 +$ や 1+ は識別子として認識することができます。 と書かれている。 ### Refs. - [Lispで変数宣言する方法 -](https://minegishirei.hatenablog.com/entry/2023/04/17/094001) - [Lispのダイナミック・スコープとスペシャル変数 · wshito's diary](https://diary.wshito.com/comp/lisp/dynamic-scope/) - [「対話によるCommon Lisp入門」第2話まとめノート · wshito's diary](https://diary.wshito.com/comp/lisp/cl-dialogue/2/) - [lisp - What's difference between defvar, defparameter, setf and setq - Stack Overflow](https://stackoverflow.com/a/8928038)