ここからは5章だ。
課題に入る前に、昨日作った o^、o/、eqan? を mymodule.scm に加えておこう。
rember*
rember* はアトム a とリスト l を引数に取り、l からすべての a を取り除いたリストを返す。これまでと違うのは、l が単純なリスト(ラットやタップ)じゃなくて、リストやリストのリストを含んだ、S式のリストだってことだ。
たとえば、(rember* 'cup '((coffee) cup ((tea) cup) (and (hick)) cup))
は ((coffee) ((tea)) (and (hick)))
になる。
(use mymodule) (define rember* (lambda (a l) (cond ((null? l) (quote ())) ((atom? (car l)) (cond ((eqan? (car l) a) (rember* a (cdr l))) (else (cons (car l) (rember* a (cdr l)))))) (else (cons (rember* a (car l)) (rember* a (cdr l))))))) (print (rember* 'cup '((coffee) cup ((tea) cup) (and (hick)) cup)))
実行:
^o^ > gosh -I. rember_star.scm ((coffee) ((tea)) (and (hick)))
insertR*
insertR* は、rember* と同じくS式のリスト l のなかのアトム old すべての右側に new を挿入する。
(use mymodule) (define insertR* (lambda (new old l) (cond ((null? l) (quote ())) ((atom? (car l)) (cond ((eqan? (car l) old) (cons old (cons new (insertR* new old (cdr l))))) (else (cons (car l) (insertR* new old (cdr l)))))) (else (cons (insertR* new old (car l)) (insertR* new old (cdr l))))))) (print (insertR* 'roast 'chuck '((hew much (wood)) could ((a (wood) chuck)) (((chuck))) (if (a) ((wood chuck))) could chuck wood)))
実行:
^o^ > gosh -I. insertR_star.scm ((hew much (wood)) could ((a (wood) chuck roast)) (((chuck roast))) (if (a) ((wo od chuck roast))) could chuck roast wood)
こっちもうまく動いているようだ。
両方の関数に共通すること
二つある。一つは、(外側の)cond の質問が三つ、(null? l)、(atom? (car l))、else だということだ。これは l が空でなければ、(car l) がアトムかリストかの両方の可能性があるから、それをチェックするためだ。(car l) がアトムでなければ(つまり else のときは)リストだ。
第1の戒律
(最終版)
アトムのリスト lat を再帰せしときは、2つの質問、(null? lat) と else を行うべし。
数 n を再帰せしときは、2つの質問、(zero? n) と else を行うべし。
S式のリスト l を再帰せしときは、3つの質問、(null? l)、(atom? (car l))、else を行うべし。
もう一つの共通点は、(car l) がリストのとき、(car l) と (cdr l) の両方で再帰している点だ。これまでは (cdr l) 出だけ再帰していたけど、(car l) もリストなんだから再帰しなければいけないってことだな。
第4の戒律
(最終版)
再帰のときは少なくとも1つの引数を変えるべし。
アトムのリスト lat を再帰せしときは、(cdr lat) を用いるべし。
数 n を再帰せしときは、(sub1 n) を用いるべし。
S式のリスト l を再帰せしときは、(null? l) も (atom? (car l)) も真でないならば、(car l) と (cdr l) を用いるべし。
必ず最終条件に向かって変化すべし。
変化せし引数は、必ず最終条件でテストすべし。すなわち、cdr を用いるときは、最後に null? で、sub1 を用いるときは、最後に zero? でテストすべし。