[1] (a) (+ (- 5 1) (+ 3 7))が評価される (- 5 1)が評価される 5が評価されて5が戻る 1が評価されて1が戻る 関数#'-に5と1が渡され4が戻る (+ 3 7)が評価される 3が評価されて3が戻る 7が評価されて7が戻る 関数#'+に3と7が渡され10が戻る 関数#'+に4と10が渡され14が戻る (b) (list 1 (+ 2 3))が評価される 1が評価されて1が戻る (+ 2 3)が評価される 2が評価されて2が戻る 3が評価されて3が戻る 関数#'+に2と3が渡され5が戻る 関数#'listに1と5が渡されて'(1 5)が戻る (c) (if (listp 1) (+ 1 2) (+ 3 4))が評価される (listp 1)が評価される 1が評価されて1が戻る --(+ 1 2)は評価されない-- (+ 3 4)が評価される 3が評価されて3が戻る 4が評価されて4が戻る 関数#'+に3と4が渡されて7が戻る ifは7を戻す Note: ifはスペシャルオペレータと呼ばれ、普通の関数とは若干扱いが異なる。 1番目の値(ここでは(listp 1))が tなら、2番目の値(ここでは(+ 1 2))のみが評価され、 nilなら、3番目の値(ここでは(+ 3 4))のみが評価される。 [2] (cons 'a '(b c)) (cons 'a (cons 'b '(c))) (cons 'a (cons 'b (cons 'c nil))) など。 [3] (defun $fourth (lst) (car (cdr (cdr (cdr lst))))) * ($fourth '(a b c d e)) => d Note: これと同じ動作をする(fourth list)という関数がある(2.4節 リストオペレータ P11)。 またcar,cdrを組み合わせた(cadddr list)という関数も同様の動作をする(3.7節 P36)。 なお、一般的にリストのn番目にアクセスするときは(nth n list)という関数を使うことが多い(3.6節 P35)。 [4] (defun larger-number (x y) (if (> x y) x y)) * (larger-number (3 5) => 5 Note: これと同じ動作が出来る関数として(max num1 num2....)という関数がある(9.3節 P131)。 例えば * (max 3 5) => 5 * (max 2 6 9 4 5 1) => 9 #'maxは何個でも引数をとれる。 [5] (a) リストxの要素にnilが含まれているかどうかを調べる関数。 nilが含まれていればtを戻す。 nilが含まれていなければnilを戻す。 * (enigma '(a b c d)) => nil * (enigma '(a nil b)) => t Note: '(a b c d)など、一般にリストの末尾はnilになっているので(3.1節)、 '(a b c d)にはnilが含まれているとも言えるが、この関数では 末尾のnilは除外して調べている((not (null x)の部分))。 その結果として、 * (enigma nil) => nil となる。 (b) アトムxがリストyの中のどの位置に含まれているかを調べる(0から数える)。 xがyの中になければnilを戻す。 * (mystery 'a '(b c a)) => 2 * (mystery 1 '(1 2 3)) => 0 * (mystery 'a '(b c d e)) => nil (6) (a) '(a (b c) d)から'bを取り出しているようである。 よってxには#'cdrが来る。 (b) (/ 1 0)は0で除算しているので、評価すればエラーになるはずだが、 エラーが発生することなく13が戻っている。 つまり、(/ 1 0)は評価されていないということである。 xにはorが入る。 Note: orはnilでない引数を見付けた時点で、評価を終了する(2.5節 P12)。 (6) ;再帰 (defun contain-list-p (list) (if (null list) nil (if (listp (car list)) t (contain-list-p (cdr list))))) ;反復(dolist) (defun contain-list-p (list) (let ((i nil)) (dolist (obj list) (if (listp obj) (setf i t) nil)) i)) Note: リストの最後まで調べているので効率が悪い。 以下、オペレータを自由に使ったもの (defun contain-list-p (list) (dolist (obj list) (if (listp obj) (return t)) nil)) Note: リストが見つかると、すぐにtを戻すように改良したもの。 (return object)は一番内のループから抜け出して、objectを戻すマクロ(5.1節 P74)。 (defun contain-list-p (list) (if (member-if #'listp list) t nil)) (8) (a) ;再帰 (defun print-dots (number) (if (= number 0) nil (progn (format t ".") (print-dots (- number 1))))) ;反復 (defun print-dots (number) (do ((i 0 (+ i 1))) ((= i number) 'done) (format t "."))) (b) ;再帰 (defun count-a (list) (if (null list) 0 (if (eql (car list) 'a) (+ 1 (count-a (cdr list))) (count-a (cdr list))))) ;反復 (defun count-a (list) (let ((number 0)) (dolist (obj list) (if (eql obj 'a) (setf number (+ number 1)))) number)) (9) (a) removeはリストの中身を変えない(非破壊関数)なので、(remove nil lst)としてもnilは消えない。 従って、 (defun summit (lst) (setf lst (remove nil lst)) (apply #'+ lst)) とすれば良いが、lstに代入しなくても (defun (apply #'+ (remove nil lst))) と出来る。 (b) lstがnilかどうか調べないので、lstの最後まで到達しても再帰し続けてしまう。 従って、 (defun summit (lst) (let ((x (car lst))) (if (null x) (if (null lst) 0 (summit (cdr lst))) (+ x (summit (cdr lst)))))) -----