来週はお休み。
Common LISPらしい特徴
(setf test-result 'test)しかし、setf のformには、もっといろいろなものを持ってくることが できる。
(setf x '(a b c d e)) (setf (car x) 'test) (setf (second x) 2)さてxの値は? setfの代入の先は、局所変数でも良い。
(defun test (x y) (setf x 3) (setf y 4) (print x) y) (test 'a 'b)さて(test 'a 'b)の結果は? xの値は? setf は入力されたデータ構造を壊してしまう。
>(defun list-destroyer (x y) (setf (cadr x) y) y ) LIST-DESTROYER >x (TEST 2 C D E) >(list-destroyer x 10) 10 >x (TEST 10 C D E)このような作用を関数の副作用といい、list-destroyerは副作用を持つという。
特に、この性質を利用して、環状リストを作ることができる。
(list-destroyer x x)しかし、テストする前に、心の準備をしておこう。
「LISP, GCLが止まらなくなったら、 control-Cを打つ。そして :q とする」
作成されたリストは、どういう 構造をしているのだろうか? 図にかいてみよう。
Pure LISPでは環状リストを作ることはできない。何故だろうか?
(defun root ( x &optional (n 2)) (expt x (/ 1 n))) (defun rest-arg (x &rest y) y) (defun key-arg (x &key y) y)
>(root 2) 1.4142135623730949 >(root 2 3) 1.2599210498948732 >(rest-arg 'a 'b 'c) (B C) >(key-arg 1 :y 3) 3
(let ((i 10)) (loop (print i) (if (= i 0) (return 0) (decf i 1)))) (do ((i 10 (- i 1))) ; 最初が10 1づつ引く ((= i 0) i) ; おわりは i が 0の時 (print i) ; これを繰り返す ) (dolist (x '(a b c d e)) (print x))しかし、loop, dolist などは確かに再帰よりはわかりやすい。 (何故だろう?)
これによって、自分独自の制御構造とかシンタックスとかを作ることが できる。Cの#define, C++のテンレートなどはマクロと考えることも できる。また、アセンブラなどではマクロによって、長く単調なコードを 読みやすくすることができる。
例えばwhile文をloopを使って書きたいとしよう。
その前に、便利なマクロを一つ紹介しよう。
(setf a 1) (setf b 2) >`(a ,a b ,b) (A 1 B 2)バックコートは、","の着いている部分だけど評価して、任意のS-式を 作ることができる。
>(defmacro while (condtion body) `(loop (if ,condtion ,body (return))) ) WHILE >(setf i 10) >(while (> i 0) (progn (decf i) (print i)))しかし、マクロには、他人には何をやっているか分からない。 デバッグが難しいという欠点がある。
マクロを使って、Common LISPをまったくLISPらくしないプログラム
に直すことができる。しかし、それはまったくLISPらしいこである...