実践CommonLispを読むその5
第六章 変数
「*」で囲むのをスペシャル変数という。他の言語ではグローバル変数とか言ったりする。
*global*
な感じですね。
新しい変数を導入する場合「let」を利用する
(let ((x 10) (y 5) z) ・・・)
xに10を、yに5を束縛する。zにはnilが束縛される。
letに関して凄いな〜と思ったのは、スコープに関すること、
(defun foo (x) (format t "Param: ~a~%" x) (let ((x 2)) (format t "Out Let: ~a~%" x) (let ((x 3)) (format t "In Let: ~a~%" x)) (format t "Out Let: ~a~%" x)) (format t "Param: ~a~%" x))
と定義して
[0]> (foo 1) Param: 1 Out Let: 2 In Let 3 Out Let: 2 Param: 1 NIL
私はこれに感動した。同様の変数名でも同じってわけじゃないんだね。letによって束縛される変数のスコープはletで束縛した範囲で有効なんだよね。ビックリだ!ちなみに「let*」ってのがあるのだが、これはなんだ?スコープの範囲が広がるのかな?
ダイナミック変数、またの名をスペシャル変数の定義は「defvar」または「defparameter」で宣言する。2つの違いは、「defparameter」は変数が評価されるたびに初期化され「defvar」は変数が未定義の場合のみ初期値を代入するだってさ、なんのこっちゃ、ん〜ちょっと理解しづらいな具体的なコードがあれば嬉しかったのだが、「defvar」の方は初期値を指定しなくてもいいようで、そういった事を未束縛と言う。
定数に関しては「defconstant」で宣言する。命名規則は「+」で変数名の前後をくくる。
(defconstant +backgroundcolor+ "#ffffff")
定数と聞くと大文字にしてみたくなるが、「+」でくくるという命名規則があればその必要はなし。処理系では大文字で処理されているだろうから関係なし。ちなみに「+」でくくるのは一般的でないそうです。
一般代入に関しては「setf」を利用する。
(setf x 10)
ちなみに「incf」や「decf」ってのもある。インクリメントやデクリメント、モディファイマクロ(modify macro)と言うみたいです。
(incf x) (decf x) (incf x 10) ; 10づつインクリメント
「rotatef」や「shiftf」もある。名前から察しが着くと思うがそんなかんじ、
変数ではやっぱり「let」が曲者だと思う。
[0]> (setf x 10) [1]> x 10 [2]> (letf x 20) [3]> x 10
だもんね。当たり前と言われればそれまでなんだが、「let」が変数を束縛するスコープを正しく理解しないと絶対に頭がおかしくなりそうだよ。LISPも以外に面白いよね。と思えるようになったかな。