リスト遊び -- Emacs で学ぶ Lisp の世界 -- 執筆後記 山本和彦 更新:2004年5月27日 ---------------------------------------------------------------- (1) p48 に掲げられている閏年を判定する関数の別実装として、以下も考えられる。 (defun leap (n) (or (= (% n 400) 0) (and (= (% n 4) 0) (/= (% n 100) 0)))) これは第3刷に入った。 ---------------------------------------------------------------- (2) 和田英一さんより p59 で出てくる memq は、メンバーであれば t を返すという仕様にしている。 (memq 2 '(1 2 3)) => t しかし、通常の Lisp では、リスト中にメンバーを発見した場合、その要素以 降のリストを返す。 (memq 2 '(1 2 3)) => (2 3) これは、返り値をできるかぎり加工しないという Lisp の思想による。他の例 としては、assq が挙げられる。 (assq 'lily '((rose . "red") (lily . "white"))) => (lily . "white") memq の仕様を Lisp の思想に沿うよう変更すべきか? それとも、今のままの 方が分かりやすいか? ---------------------------------------------------------------- (3) 藤井宏憲さんより p66 に出てくる sum* の実装は、以下の方が原書のプログラムよりも美しい。 (defun sum* (lst) (cond ((null lst) 0) ((atom lst) lst) (t (+ (sum* (car lst)) (sum* (cdr lst)))))) これを導くためには、sum の定義を以下のようにして、拡張する必要がある。 (defun sum (lst) (cond ((null lst) 0) ((atom lst) lst) (t (+ (sum (car lst)) (sum (cdr lst)))))) しかしながら、上記は sum の定義としては冗長だと思う。 ちなみに原書のプログラムは以下のような感じ。 (defun sum (lst) (cond ((null lst) 0) (t (+ (car lst) (sum (cdr lst)))))) (defun sum* (lst) (cond ((null lst) 0) ((consp (car lst)) (+ (sum* (car lst)) (sum* (cdr lst)))) (t (+ (car lst) (sum* (cdr lst)))))) ---------------------------------------------------------------- (4) 4 章に最大公約数を計算するプログラムも載せるべきか? gcd(a, b) = gcd(b, a % b), a >= b gcd(a, 0) = a (defun gcd (a b) (cond ((= b 0) a) (t (gcd b (% a b))))) アルゴリズムの王様だけに、学んだ人は多いが、再帰で書けることを 知っている人は少ないだろう。 ---------------------------------------------------------------- (5)芳賀秀雄さんより p48 の「and」の説明は以下のようになっている。 ---- すべての式がnil以外の値になった場合に限り、最後の式の値を返します。 つまりこれは真を表します。 ---- しかしながら、最初からずっと式の値が nil 以外となり、最後の式だけがnil の場合、最後の nil が返ると考えることもできる。(文脈により、これが取り 除かれているのは明らかであるが、ここだけ見ると混乱する。) 「限り」には、「and が真を返す」条件を限定したいという気持が含まれてい る。以下のように書き直せば、文脈に依存しない表現となる。 ---- nil 以外が返されるのは、すべての式が nil 以外の値になった場合に限ります。 このときの and の返す値は、最後の式の値です。これは nil 以外ですから、 真を表します。 ---- 第5刷が出版されるなら、こう変更したいと思う。 以上