rember は remove member の略だそうだ。関数 rember はアトム a とリスト lat を引数に取って、lat の中の一番最初に現れる a と同じアトムを取り除いたリストを返す。
本文 p.35 には次のような定義が載っている。
(define rember (lambda (a lat) (cond ((null? lat) (quote ())) (else (cond ((eq? (car lat) a) (cdr lat)) (else (rember a (cdr lat))))))))
試してみよう。
gosh> (rember 'bacon '(bacon lettuce and tomato)) (lettuce and tomato)
うまく動いたようだ。
だけど、次の例では期待どおりにはいかない。
gosh> (rember 'and '(bacon lettuce and tomato)) (tomato)
期待した結果は (bacon lettuce tomato) のはず。おかしいのは7行目の再帰の部分だ。再帰を使ってリスト lat の要素をひとつずつ見ていっていきながら a と同じアトムを探しているんだけど、7行目の (rember a (cdr lat)) は再帰するさいに a と同じでないアトム、つまり取り除くべきでないアトムを捨ててしまっている。
ということは、捨てるべきでないアトムを先頭にくっつけてやればいい。どうやるかっていうと、cons を使えばいい。修正したのがこれ。
(define rember (lambda (a lat) (cond ((null? lat) (quote ())) (else (cond ((eq? (car lat) a) (cdr lat)) (else (cons (car lat) (rember a (cdr lat)))))))))
試してみよう。
gosh> (rember 'and '(bacon lettuce and tomato)) (bacon lettuce tomato)
今度は期待どおりに動いた。
第2の戒律
リストを作るには cons を用いるべし。
おまけ。cond は質問とそれに対応する値の組をいくつでもとれるので、それを使って次のように簡単化した定義が載っている(p.41)。
(define rember (lambda (a lat) (cond ((null? lat) (quote ())) ((eq? (car lat) a) (cdr lat)) (else (cons (car lat) (rember a (cdr lat)))))))
実行例:
gosh> (rember 'sauce '(soy sauce and tomato sauce)) (soy and tomato sauce)
「rember」への1件のフィードバック