lat?
関数 lat? は、引数にリストを取り、そのリストがラット(要素すべてがアトムであるか空であるリスト)のとき #t を返し、そうでないときには #f を返す。
「Scheme手習い」本文(p.16)では次のように定義されている(関数 atom? は定義済みとして)。
(define lat?
(lambda (l)
(cond
((null? l) #t)
((atom? (car l)) (lat? (cdr l)))
(else #f))))
再帰が出てきた。関数 cond は複数の質問とその質問に対応する値をとり、結果として真となる質問に対応する値を返す。ここではふたつ目の質問 (atom? (car l))
に対応する値 (lat? (cdr l))
の部分が再帰になっている。
いくつか試してみよう。
gosh> (lat? '(Jack Sprat could eat no chicken fat))
#t
gosh> (lat? '((Jack) Sprat could eat no chicken fat))
#f
gosh> (lat? '(Jack (Sprat could) eat no chicken fat))
#f
gosh> (lat? '())
#t
ところで、このラットという用語は Scheme の用語なのか、この本の中でそう呼んでいるだけなのか、ググってみてもよくわからなかった。まあいいか。
member?
関数 member? はアトムとリストを引数に取り、アトムがリストのメンバーであるとき #t を返す。member? の定義は次のようになる(p.23)。
(define member?
(lambda (a lat)
(cond
((null? lat) #f)
(else (or (eq? (car lat) a)
(member? a (cdr lat)))))))
ここで誤植発見。本文では4行目が ((null? lat) nil)
となっているけど、nil じゃなくて #f の間違いだろう。たぶん。
さて、新しい関数 or が出てきた。or は引数をふたつ取り、どちらかが真であれば #t を返す。このとき、ひとつ目の引数が真であれば、ふたつ目の引数は評価されない。
それから6行目ではまたも再帰が出てきている。それじゃ、いくつか試してみよう。
gosh> (member? 'tea '(coffee tea or milk))
#t
gosh> (member? 'poached '(fried eggs and scrambled eggs))
#f
関係ないけど poached eggs ってのは落とし卵のことのようだ。うちじゃよく味噌汁に入ってる。
再帰とnull?
lat? と member? に共通するのは、リストの要素をひとつずつ、(必要であれば)最後まで見て返す答えを決定することだ。cond のひとつ目の質問には両方の関数で (null? l) が使われている。これでリストの最後に到達したかどうかを判定している。
第1の戒律
(仮)いかなる関数を表現するときも最初の質問はすべて null? にすべし。