実践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も以外に面白いよね。と思えるようになったかな。