ANSI Common Lisp 2章「Lispの世界へようこそ」
練習問題があったので,解いてみた.
4 2つの数を引数として,大きい方を返す関数
(defun my-max (lst) (if (not (cdr lst)) (car lst) (if (> (car lst) (my-max (cdr lst))) (car lst) (my-max (cdr lst)))))
折角だからリストを受け取るようにした.そしたらすげぇごちゃごちゃした.気持ち悪いよ.しかもリストを渡すわけだから,
(my-max (list 1 3 2 4)) ;; maxなら, (max 1 3 2 4) で良い
なんてしなければいけないという手間.任意個の引数をとる方法が,きっとあるはず.
7 引数のリストにリストが含まれているか
(defun haslist (lst) (or (listp (car lst)) (if (cdr lst) (haslist (cdr lst)))))
んー,現時点ではこれが限界です.
8 再帰
反復と再帰を使ってa,bを解かなければならないけれど,再帰だけにしておく.
a 正の整数を引数とし,その数のドットを表示
(defun dot (x) (if (> x 0) (funcall #'(lambda () (format t ".") (dot (- x 1))))))
のっけからlambdaが出てくるこの本はほんと素敵だと思うんだけど,common lispを学ぶ上では,至極普通なのかな.
b リストにaというシンボルが幾つ含まれているか
(defun counta (lst) (if (car lst) (if (eql 'a (car lst)) (+ 1 (counta (cdr lst))) (counta (cdr lst))) 0))
最後の0がきもいね!
9 nilでない要素の合計
二通り,間違いのコードがあって,それを正そうという問題.
a
まずは間違い.
(defun summit (lst) (remove nil lst) (apply #'+ lst))
どの辺が間違いかというと,
- removeしたところでlstに変更は加えられない.せめて(setf (remove nil lst))とすべき
- "+"じゃリストの長さは数えられないじゃね?
で,こうした.
(defun summit (lst) (length (remove nil lst)))
b
まずは間違い.
(defun summit (lst) (let ((x (car lst))) (if (null x) (summit (cdr lst)) (+ x (summit (cdr lst))))))
どの辺が間違いかというと,
- 再帰だけど止まらない
- 最後の行,xを足してどうする
- となると,xは使わなくなるのでlet不要
で,足りない頭を精一杯使ってこうした.
(defun summit (lst) (if (cdr lst) (if (null (car lst)) (summit (cdr lst)) (+ 1 (summit (cdr lst)))) (if (null (car lst)) 0 1)))
とりあえず動く.そりゃごり押しだもん.
第3章では,リストについて詳しく説明してくれるそうです.