subset?とeqset?

※追記あり

subset?

s1、s2 のセット2つを引数にとり、s1 が s2 のサブセット(部分集合)のとき #t を返す関数。

(use mymodule)

(define subset?
  (lambda (s1 s2)
    (cond
      ((null? s1) #t)
      ((member? (car s1) s2) (subset? (cdr s1) s2))
      (else #f))))

(print (subset? '(5 chicken wings)
                '(5 hamburgers 2 pieces fried chicken and light duckling wings)))
(print (subset? '(4 pounds of horseradish)
                '(four pounds chicken and 5 ounces horseradish)))
^o^ > gosh -I. subset.scm
#t
#f

eqset?

2つのセット s1 と s2 が等しければ #t を返す関数。お互いがお互いのサブセットなら、等しいといえる。これをコードにするとこうなる。

(use mymodule)

(define subset?
  (lambda (s1 s2)
    (cond
      ((null? s1) #t)
      ((member? (car s1) s2) (subset? (cdr s1) s2))
      (else #f))))

(define eqset?
  (lambda (s1 s2)
    (cond
      ((subset? s1 s2) (subset? s2 s1))
      (else #f))))

(print (eqset? '(6 large chickens with wings)
               '(6 chickens with large wings)))
^o^ > gosh -I. eqset.scm
#t

and を使うともっと短くなる。eqset? だけ示すと:

(define eqset?
  (lambda (s1 s2)
    (cond
      (else (and (subset? s1 s2) (subset? s2 s1))))))

こうなると cond はいらなくなるので、もっと短くなる。

(define eqset?
  (lambda (s1 s2)
    (and (subset? s1 s2) (subset? s2 s1))))

3行になった。

追記

subset? も and を使うと短くなる。

(use mymodule)

(define subset?
  (lambda (s1 s2)
    (cond
      ((null? s1) #t)
      (else (and (member? (car s1) s2) (subset? (cdr s1) s2))))))

(print (subset? '(5 chicken wings)
                '(5 hamburgers 2 pieces fried chicken and light duckling wings)))
(print (subset? '(4 pounds of horseradish)
                '(four pounds chicken and 5 ounces horseradish)))
^o^ > gosh -I. subset2.scm
#t
#f

set?とmakeset

今日から7章。集合(セット)が出てきた。セットは、同じアトムが2回以上現れないリストのこと。
まずは、引数として与えられたリストが、セットかどうかを判定する関数 set? から。

set?

(define member?
  (lambda (a lat)
    (cond
      ((null? lat) #f)
      (else (or (eq? (car lat) a) (member? a (cdr lat)))))))

(define set?
  (lambda (lat)
    (cond
      ((null? lat) #t)
      ((member? (car lat) (cdr lat)) #f)
      (else (set? (cdr lat))))))

(print (set? '(apple peaches apple plum)))
(print (set? '(apples peaches pears plums)))
(print (set? '(apple 3 pear 4 9 apple 3 4)))

実行:

^o^ > gosh set.scm
#f
#t
#f

うまくいった。と思ったら、ページ(p.133)の下のほうのやり取りで、「これは次のデータに対してもうまく動きますか。 (apple 3 pear 4 9 apple 3 4)」「はい、member? は eq? ではなく equal? を使って書かれていますから。」とある。いつのまに書き直したんだ、と思って本を読み直したら、5章の最後のやり取りで書き直したことになっているらしい(ほかに該当するところが見当たらない)。この本では eq? は数ではないアトムを引数にとることになっている(eq? の掟)。
とはいえ、実際には eq? は引数が数でも正しく動くので、本と実際とでくい違ってしまっているわけだ。ま、いいか。一応、equal? を使った member? を載せておく。

(use mymodule)

(define member?
  (lambda (a lat)
    (cond
      ((null? lat) #f)
      (else (or (equal? (car lat) a) (member? a (cdr lat)))))))

これも mymodule.scm に追加しておこう。

makeset

次はリストからセットを作る makeset。

(use mymodule)

(define makeset
  (lambda (lat)
    (cond
      ((null? lat) (quote ()))
      ((member? (car lat) (cdr lat)) (makeset (cdr lat)))
      (else (cons (car lat) (makeset (cdr lat)))))))

(print (makeset '(apple peach pear peach plum apple lemon peach)))

実行:

^o^ > gosh -I. makeset.scm
(pear plum apple lemon peach)

OK。では次に multirember を使って makeset を書け、と。この multirember も equal? を使って書くみたいだな。

(use mymodule)

(define multirember
  (lambda (a lat)
    (cond
      ((null? lat) (quote ()))
      ((equal? (car lat) a) (multirember a (cdr lat)))
      (else (cons (car lat) (multirember a (cdr lat)))))))

(define makeset
  (lambda (lat)
    (cond
      ((null? lat) (quote ()))
      (else (cons (car lat) (makeset (multirember (car lat) (cdr lat))))))))

(print (makeset '(apple peach pear peach plum apple lemon peach)))
^o^ > gosh -I. makeset2.scm
(apple peach pear plum lemon)

うまく動いた。けど、この実装での結果が本(p.144)と違っている。たぶん間違っているのは本のほう。だって、makeset の2つの定義では違う動作をするはずなのに、本では結果が同じになってるから。

可変長の引数をとる関数

Scheme手習いからはちょっと脱線して、可変長の引数をとる関数の定義方法。
このページが参考になった。

 cf. 可変長引数をとる関数の定義法 ― チキン煮込みチーズミックス4辛
 cf. 4.3 手続きを作る ― Gauche ユーザリファレンス

2個以上の引数をとる関数

次のように定義する。

(define func
  (lambda (a b . c)
    (print "a= " a " b= " b " c= " c)))

(func 1 2)
(func 1 2 3 4)

2行目のように引数リストの最後の直前に ‘.’ を入れて書く。こうすると、a、b には最初の2個の引数が渡され、c には残りの引数がリストとして渡される。

^o^ > gosh args2.scm
a= 1 b= 2 c= ()
a= 1 b= 2 c= (3 4)

1個以上の引数をとる関数

2個以上の引数を取る関数と本質的に同じ。

(define func
  (lambda (a . b)
    (print "a= " a " b= " b)))

(func 1)
(func 1 2 3 4)
^o^ > gosh args1.scm
a= 1 b= ()
a= 1 b= (2 3 4)

0個以上の引数をとる関数

これは上の場合と違う。通常、仮引数は括弧でくくってリストの形にするけど、引数が0個以上の場合には括弧でくくらない。

(define func
  (lambda a
    (print "a= " a)))

(func)
(func 1)
(func 1 2 3 4)

こうすると、引数はすべて a にリストとして渡される。

^o^ > gosh args0.scm
a= ()
a= (1)
a= (1 2 3 4)

空リストで数を表現する

6章の最後に、空リストで数を表現するという面白いのが出てくる。
たとえば 0 は ()、1 は (())、2 は (() ()) という具合だ。この数の表現を使っていくつか関数を書いてみよう。
まずは、ゼロかどうかを調べる関数。

gosh> (define sero?
  (lambda (n)
    (null? n)))
sero?
gosh> (sero? '())
#t
gosh> (sero? '(()))
#f

つぎに、add1 に相当する関数。

gosh> (define edd1
  (lambda (n)
    (cons (quote ()) n)))
edd1
gosh> (edd1 '())
(())
gosh> (edd1 '(() ()))
(() () ())

sub1 に相当する関数。

gosh> (define zub1
  (lambda (n)
    (cdr n)))
zub1
gosh> (zub1 '(() ()))
(())
gosh> (zub1 '())
*** ERROR: pair required, but got ()
Stack Trace:
_______________________________________

ゼロ () に zub1 を適用したらエラーになった。0 以上の整数しか扱えないんだな。

算術式の別表現とvalue

6章の続き。算術式の別の表現というのが出てくる。この別の表現というのは次のようなもの。

  • +の後に2つの算術式が続いたリスト
  • ×の後に2つの算術式が続いたリスト
  • ↑の後に2つの算術式が続いたリスト

この新しい算術式の値を求める関数 value を書け、と。
こんなのでどうだ。

(use mymodule)

(define value
  (lambda (nexp)
    (cond
      ((atom? nexp) nexp)
      ((eq? (car nexp) (quote e+))
      (o+ (value (car (cdr nexp))) (value (car (cdr (cdr nexp))))))
      ((eq? (car nexp) (quote e*))
      (o* (value (car (cdr nexp))) (value (car (cdr (cdr nexp))))))
      (else
        (o^ (value (car (cdr nexp))) (value (car (cdr (cdr nexp)))))))))

(print (value '(e+ 3 8)))
(print (value '(e+ (e* 3 6) (e^ 8 2))))

実行:

^o^ > gosh -I. value2.scm
11
82

うまくいったようだ。
さて、書いてみたコードを見ると、car や cdr が多すぎる。ここで、本(「Scheme手習い」)では、第1の算術式を求める 1st-sub-exp、第2の算術式を求める 2nd-sub-exp、演算子にあたる部分を求める operator を書き、これらを使って value を書き直せ、とある。やってみよう。

(use mymodule)

(define 1st-sub-exp
  (lambda (aexp)
    (car (cdr aexp))))

(define 2nd-sub-exp
  (lambda (aexp)
    (car (cdr (cdr aexp)))))

(define operator
  (lambda (aexp)
    (car aexp)))

(define value
  (lambda (nexp)
    (cond
      ((atom? nexp) nexp)
      ((eq? (operator nexp) (quote e+))
        (o+ (value (1st-sub-exp nexp)) (value (2nd-sub-exp nexp))))
      ((eq? (operator nexp) (quote e*))
        (o* (value (1st-sub-exp nexp)) (value (2nd-sub-exp nexp))))
      (else
        (o^ (value (1st-sub-exp nexp)) (value (2nd-sub-exp nexp)))))))

(print (value '(e+ 3 8)))
(print (value '(e+ (e* 3 6) (e^ 8 2))))

実行:

^o^ > gosh -I. value3.scm
11
82

うまくいった。

最後に、今書いたコードを、最初の算術式の表現、つまり演算子に当たるアトムが中置きに成っている算術式の表現に合うように直せるか、ときた。
これは簡単、1st-sub-exp と operator を書き直せばいい。

(define 1st-sub-exp
  (lambda (aexp)
    (car aexp)))

(define operator
  (lambda (aexp)
    (car (cdr aexp))))

value は書き直す必要がない。なぜなら、value は 1st-sub-exp、2nd-sub-exp、operator という3つの補助関数を使って抽象化されているからだ。こうやって抽象化しておけば、算術式の表現が変わっても補助関数を直すだけでいい、というわけだな。

第8の戒律
表現から抽象化するに際し、補助関数を使用すべし。

numbered?とvalue

算術式と算術式の表現

今日から6章だ。算術式と、算術式の表現という言葉が出てきた。算術式とは(数を含む)アトムか、2つの算術式を+か×か↑で結合したもの。一方、算術式の表現とは算術式を括弧でくくったものだ。
例を示そう。まずは算術式の例:

  • 1
  • 1 + 3
  • 1 + 3 × 4
  • 3 ↑ y + 5

ここで注意しておかなきゃいけないのは、+や×、↑ はアトムであって前に書いた演算子(o+とかo*とか書いたやつ)ではないってこと。
それから算術式の表現の例:

  • 1
  • (1 + 3)
  • (1 + (3 × 4))
  • ((3 ↑ y) + 5)

ポイントは、括弧でくくったことでS式になったところだ。1 はアトムなので括弧でくくらなくてもS式だ。算術式がS式になったことで Scheme で扱えるようになった。

numbered?

関数 numbered? は算術式の表現、つまりS式が、+、×、↑ を除いて数だけを含むかどうかを判定する関数。特殊文字は使えないので、これからは e+、e*、e^ (e は expression の e)と書こう。
p.101 にヒントがあるので、numbered? を書いてみよう。

(use mymodule)

(define numbered?
  (lambda (aexp)
    (cond
      ((atom? aexp) (number? aexp))
      ((eq? (car (cdr aexp)) (quote e+))
        (and (numbered? (car aexp)) (numbered? (car (cdr (cdr aexp))))))
      ((eq? (car (cdr aexp)) (quote e*))
        (and (numbered? (car aexp)) (numbered? (car (cdr (cdr aexp))))))
      (else
        (and (numbered? (car aexp)) (numbered? (car (cdr (cdr aexp)))))))))

(print (numbered? 1))
(print (numbered? '(1 e+ 3)))
(print (numbered? '(1 e+ (3 e* 4))))
(print (numbered? '((3 e^ 2) e+ 5)))

実行してみよう:

^o^ > gosh -I. numbered.scm
#t
#t
#t
#t

うまくいったようだ。

value

関数 value は算術式の自然な値を返す関数。たとえば (value (1 e+ 2)) は 3 を返す。これもヒントを見ながら書いてみよう。

(use mymodule)

(define value
  (lambda (nexp)
    (cond
      ((atom? nexp) nexp)
      ((eq? (car (cdr nexp)) (quote e+))
        (o+ (value (car nexp)) (value (car (cdr (cdr nexp))))))
      ((eq? (car (cdr nexp)) (quote e*))
        (o* (value (car nexp)) (value (car (cdr (cdr nexp))))))
      (else
        (o^ (value (car nexp)) (value (car (cdr (cdr nexp)))))))))

(print (value 1))
(print (value '(1 e+ 3)))
(print (value '(1 e+ (3 e* 4))))
(print (value '((3 e^ 2) e+ 5)))

実行:

^o^ > gosh -I. value.scm
1
4
13
14

OKだ。

numbered?とvalueに共通すること

2つの関数、numbered? と value に共通するのは、引数がアトムでなかった場合、算術式の2つの部分式について再帰するところだ。部分式が算術式であるかどうかがわかれば全体が算術式であるかどうかもわかるし、部分式の値がわかれば全体の値もわかる。

第7の戒律
性質を同じくするすべての構成部分について再帰すべし。

  • リストのすべての部分リストについて。
  • 算術式のすべての部分式について。

S式を取り除くrember

5章もこれで最後だ。
つい先日、ラット lat の中からアトム a を取り除く関数 rember を書いた。今度は、この rember をS式のリスト l からS式 s を取り除くように書き直すと次のようになる。
(おっと、その前に equal? と eqlist? を mymodule.scm に加えておこう)

(use mymodule)

(define rember
  (lambda (s l)
    (cond
      ((null? l) (quote ()))
      ((atom? (car l))
      (cond
        ((equal? (car l) s) (cdr l))
        (else (cons (car l) (rember s (cdr l))))))
      (else
        (cond
          ((equal? (car l) s) (cdr l))
          (else (cons (car l) (rember s (cdr l)))))))))

(print (rember '(cup) '((coffee (cup)) tea (cup) and ((hick) cup))))
^o^ > gosh -I. rember2.scm
((coffee (cup)) tea and ((hick) cup))

これを簡単化せよ、と。まあ、難しくはない。equal? は任意のS式を比較できるんだから、(atom? (car l)) の条件は必要ない。というわけでこうなる。

(use mymodule)

(define rember
  (lambda (s l)
    (cond
      ((null? l) (quote ()))
      (else
        (cond
          ((equal? (car l) s) (cdr l))
          (else (cons (car l) (rember s (cdr l)))))))))

(print (rember '(cup) '((coffee (cup)) tea (cup) and ((hick) cup))))
^o^ > gosh -I. rember3.scm
((coffee (cup)) tea and ((hick) cup))

さて、まだ簡単化できる。cond が二重になっているのが冗長だから、ひとつにしてしまえばいい。

(use mymodule)

(define rember
  (lambda (s l)
    (cond
      ((null? l) (quote ()))
      ((equal? (car l) s) (cdr l))
      (else (cons (car l) (rember s (cdr l)))))))

(print (rember '(cup) '((coffee (cup)) tea (cup) and ((hick) cup))))

だいぶ簡単になった。うまく動くか試してみよう。

^o^ > gosh -I. rember4.scm
((coffee (cup)) tea and ((hick) cup))

OK!これで5章は終わり。

eqlist?

eqlist?

eqlist? はS式のリスト l1 と l2 が等しければ #t を返し、そうでなければ #f を返す。
今度はちょっと、いやだいぶややこしい。少しずついこう。
まず、本文で質問が9つあるといっているのは、l1、l2 とも次の3つの状態が考えられて、その組み合わせが9つある、ということだ。

  • 空リスト
  • アトムがリストに cons されたもの
  • リストが別のリストに cons されたもの

これにしたがってスクリプトを書く(というか写経する)と:

(use mymodule)

(define eqlist?
  (lambda (l1 l2)
    (cond
      ((and (null? l1) (null? l2)) #t)
      ((and (null? l1) (atom? (car l2))) #f)
      ((null? l1) #f)
      ((and (atom? (car l1)) (null? l2)) #f)
      ((and (atom? (car l1)) (atom? (car l2)))
      (and (eqan? (car l1) (car l2)) (eqlist? (cdr l1) (cdr l2))))
      ((atom? (car l1)) #f)
      ((null? l2) #f)
      ((atom? (car l2)) #f)
      (else
        (and (eqlist? (car l1) (car l2)) (eqlist? (cdr l1) (cdr l2)))))))

(print (eqlist? '(strawberry ice cream) '(strawberry cream ice)))
(print (eqlist? '(banana ((split))) '((banana) (split))))
(print (eqlist? '(beef ((sausage)) (and (soda))) '(beef ((sausage)) (and (soda)))))

ファイル名は eqlist.scm とした。
9つの条件をひとつずつ cond の質問に置き換えている。最初の3つの質問(1~3番目)は l1 が空リストの場合、次の3つの質問(4~6番目)が l1 がアトムがリストに cons されたものの場合、else を含む最後の3つの質問(7~9番目)が l1 がリストが別のリストに cons された場合だ。

^o^ > gosh -I. eqlist.scm
#f
#f
#t

ここまではOK、難しくない。ところがこのあとの本文のやり取りはちょっと腑に落ちない。p.94には「式 (and (null? l1) (null? l2)(or (null? l1) (null? l2)) が、最初の3つの場合にきちんと答を出すという意味ですか。」「はい。」とある。腑に落ちないのは「最初の3つの場合」の部分だ。これは質問の1~3をさしているのだろけど、この3つは l1 が空リストの場合だ。だけど、(or (null? l1) (null? l2)) は l1 が空リストじゃなくても l2 が空リストなら真となる。つまり、この部分は質問の2~3だけじゃなくて、質問4((and (atom? (car l1)) (null? l2)))と質問7((null? l2))も含んでいるわけだ。そしてそのすべての場合に #f になる。これで l1 か l2 と少なくとも一方が空リストの場合を網羅したことになる。

ここで、書き直した eqlist? が出てくる(p.94)。ファイル名は eqlist2.scm としよう。

(use mymodule)

(define eqlist?
  (lambda (l1 l2)
    (cond
      ((and (null? l1) (null? l2)) #t)
      ((or (null? l1) (null? l2)) #f)
      ((and (atom? (car l1)) (atom? (car l2)))
        (and (eqan? (car l1) (car l2)) (eqlist? (cdr l1) (cdr l2))))
      ((or (atom? (car l1)) (atom? (car l2))) #f)
      (else
        (and (eqlist? (car l1) (car l2)) (eqlist? (cdr l1) (cdr l2)))))))

(print (eqlist? '(strawberry ice cream) '(strawberry cream ice)))
(print (eqlist? '(banana ((split))) '((banana) (split))))
(print (eqlist? '(beef ((sausage)) (and (soda))) '(beef ((sausage)) (and (soda)))))

見るとわかるように最初の eqlist? では9つあった質問が5つになっている。
もう一点、or を使った質問が2つある。1つ目は上に書いたとおり、l1 と l2 のどちらか一方だけが空リストの場合、2つ目の or は (car l1) と (car l2) のどちらか一方だけがアトムの場合だ。これは最初の eqlist? の質問6と8に相当する。
1つ目の or で質問が3つ、2つ目の or で質問が1つ減って、質問は9つから5つになったわけだな。
正しく動くか試してみよう。

^o^ > gosh -I. eqlist2.scm
#f
#f
#t

OKのようだ。

equal?

equal? はアトムかリスト(すなわちS式)2つを引数にとって、等しければ #t、そうでなければ #f を返す。

(use mymodule)

(define equal?
  (lambda (s1 s2)
    (cond
      ((and (atom? s1) (atom? s2)) (eqan? s1 s2))
      ((atom? s1) #f)
      ((atom? s2) #f)
      (else (eqlist? s1 s2)))))

ここで、2番目と3番目の質問は冗長だ。1番目の質問が真にならなければ、s1 と s2 のどちらかはアトムではないのがわかっているんだから、2つをまとめて (or …) とできる。

(use mymodule)

(define equal?
  (lambda (s1 s2)
    (cond
      ((and (atom? s1) (atom? s2)) (eqan? s1 s2))
      ((or (atom? s1) (atom? s2)) #f)
      (else (eqlist? s1 s2)))))

もう一度、eqlist?

equal? があれば eqlist? をもっと簡単にできる。equal? は引数がアトムかリストかを気にせずに比較できるのだから、eqlist2.scm の9~11行目を省略できるわけだ。equal? を使って書き直した eqlist? は次のようになる(ファイル名は eqlist3.scm)。

(use mymodule)

(define equal?
  (lambda (s1 s2)
    (cond
      ((and (atom? s1) (atom? s2)) (eqan? s1 s2))
      ((or (atom? s1) (atom? s2)) #f)
      (else (eqlist? s1 s2)))))

(define eqlist?
  (lambda (l1 l2)
    (cond
      ((and (null? l1) (null? l2)) #t)
      ((or (null? l1) (null? l2)) #f)
      (else
        (and (equal? (car l1) (car l2)) (eqlist? (cdr l1) (cdr l2)))))))

(print (eqlist? '(strawberry ice cream) '(strawberry cream ice)))
(print (eqlist? '(banana ((split))) '((banana) (split))))
(print (eqlist? '(beef ((sausage)) (and (soda))) '(beef ((sausage)) (and (soda)))))

うまく動くか試してみよう。

^o^ > gosh -I. eqlist3.scm
#f
#f
#t

大丈夫のようだ。

第6の戒律
関数が正しいときのみ簡単化せよ。

leftmost

leftmost は空リストを含まない空リストの中で最も左にあるアトムを返す。
この関数は今までの関数とはちょっと違う。最も左のアトムを返すのだから (car l) でだけ再帰する。もう一つ、「空リストを含まない空リスト」という条件がついているから、必ずアトムが見つかるはず、言い換えると atom? が最終条件となる。
それじゃ書いてみよう。

(use mymodule)

(define leftmost
  (lambda (l)
    (cond
      ((atom? (car l)) (car l))
      (else (leftmost (car l))))))

(print (leftmost '((potato) (chips ((with) fish) (chips)))))
(print (leftmost '(((hot) (tuna (and))) cheese)))

実行:

^o^ > gosh -I. leftmost.scm
potato
hot

occur*、subst*、insertL*、member*

どんどんいこう。

occure*

occure* はS式のリスト l の中にアトム a がいくつあるかを返す。

(use mymodule)

(define occur*
  (lambda (a l)
    (cond
      ((null? l) 0)
      ((atom? (car l))
        (cond
          ((eqan? (car l) a) (add1 (occur* a (cdr l))))
          (else (occur* a (cdr l)))))
      (else (o+ (occur* a (car l)) (occur* a (cdr l)))))))

(print (occur* 'banana
               '((banana)
               (split ((((banana ice)))
               (cream (banana))
               sherbe))
  (banana)
  (bread)
  (banana brandy))))
^o^ > gosh -I. occur_star.scm
5

subst*

subst* は、S式のリスト l の中のアトム old すべてを new に置き換える。

(use mymodule)

(define subst*
  (lambda (new old l)
    (cond
      ((null? l) (quote ()))
      ((atom? (car l))
        (cond
          ((eqan? (car l) old) (cons new (subst* new old (cdr l))))
          (else (cons (car l) (subst* new old (cdr l))))))
      (else (cons (subst* new old (car l)) (subst* new old (cdr l)))))))

(print (subst* 'orange
               'banana
               '((banana)
                 (split ((((banana ice)))
                 (ceam (banana))
                 sherbet))
  (banana)
  (bread)
  (banana brandy))))
^o^ > gosh -I. subst_star.scm
((orange) (split ((((orange ice))) (ceam (orange)) sherbet)) (orange) (bread) (o
range brandy))

insertL*

insertL* はS式のリストの中のアトム old すべての左に new を挿入する。

(use mymodule)

(define insertL*
  (lambda (new old l)
    (cond
      ((null? l) (quote ()))
      ((atom? (car l))
        (cond
          ((eqan? (car l) old) (cons new (cons old (insertL* new old (cdr l)))))
          (else (cons (car l) (insertL* new old (cdr l))))))
      (else
        (cons (insertL* new old (car l)) (insertL* new old (cdr l)))))))

(print (insertL* 'roast
                 'chuck
                 '((hew much (wood))
                 could
                 ((a (wood) chuck))
                 (((chuck)))
  (if (a)
      ((wood chuck)))
      could chuck wood)))
^o^ > gosh -I. insertL_star.scm
((hew much (wood)) could ((a (wood) roast chuck)) (((roast chuck))) (if (a) ((wo
od roast chuck))) could roast chuck wood)

member*

member* は、S式のリストの中にアトム a があれば #t を返し、そうでなければ #f を返す。

(use mymodule)

(define member*
  (lambda (a l)
    (cond
      ((null? l) #f)
      ((atom? (car l))
      (cond
        ((eqan? (car l) a) #t)
        (else (member* a (cdr l)))))
      (else (or (member* a (car l)) (member* a (cdr l)))))))

(print (member* 'chips '((potato) (chips ((with) fish) (chips)))))
^o^ > gosh -I. member_star.scm
#t