Scheme手習い (5) 数のリスト
次は数のリストを扱います
数のリストはタップ(tup)と呼ばれています
扱い方はラットとほとんど同じ
タップに含まれる数の合計を返すaddtup
(define addtup
(lambda (tup)
(cond ((null? tup) 0)
(else (o+ (car tup) (addtup (cdr tup)))))))
()の代わりに0、consの代わりにo+を使っています
(addtup '(3 5 2 8))
(o+ 3 (addtup '(5 2 8)))
(o+ 3 (o+ 5 (addtup '(2 8))))
(o+ 3 (o+ 5 (o+ 2 (addtup '(8)))))
(o+ 3 (o+ 5 (o+ 2 (o+ 8 (addtup '())))))
(o+ 3 (o+ 5 (o+ 2 (o+ 8 0))))
(o+ 3 (o+ 5 (o+ 2 8)))
18
次は二つのタップを項目ごとに加算して和のリストを作るtup+
第1版は二つのタップの長さが同じであるという仮定をおいたバージョンです
(define tup+
(lambda (tup1 tup2)
(cond ((and (null? tup1) (null? tup2)) (quote ()))
(else (cons (o+ (car tup1) (car tup2))
(tup+ (cdr tup1) (cdr tup2)))))))
実行の様子
(tup+ '(1 2 3) '(4 5 6))
(cons 5 (tup+ '(2 3) '(5 6)))
(cons 5 (cons 7 (tup+ '(3) '(6))))
(cons 5 (cons 7 (cons 9 (tup+ '() '()))))
(cons 5 (cons 7 (cons 9 '())))
'(5 7 9)
仮定を外した第2版
長さが異なる場合の処理が((null? tup1) tup2)と一発で終わるのが気持ちいいです
tup1もtup2も()であれば、((null? tup1) tup2)で()が返されるので
特別な処理も必要ありません
(define tup+
(lambda (tup1 tup2)
(cond ((null? tup1) tup2)
((null? tup2) tup1)
(else (cons (o+ (car tup1) (car tup2))
(tup+ (cdr tup1) (cdr tup2)))))))
タップの長さが違う例で確かめます
(tup+ '(1 2) '(3 4 5 6))
(cons 4 (tup+ '(2) '(4 5 6)))
(cons 4 (cons 6 (tup+ '() '(5 6))))
(cons 4 (cons 6 '(5 6)))
(cons 4 '(6 5 6))
'(4 6 5 6)
少しずつパターンを変えながら、ラットの長さを求めるlength、ラットのn番目の要素を
抽出するpick、ラットのn番目の要素を削除するrempickを作ります
少しずつ違うとはいえこのあたりはもうお手の物
次は引数が数であるかどうかを判定するnumber?のご紹介
これはschemeにもともと備わっている基本関数で、他の関数で表すことはできません
使い方の例として、ラットから数を消すno-numsとラットから数字だけを取り出すall-numsを作ります
これも問題ありません
o=は数だけ、eq?は数以外のアトムだけしか比べられません1
数でもアトムでも等しいかどうかを判定できるeqan?を作ります
o=は数だけ、eq?は数以外のアトムだけしか比べられませんので
あらかじめnumber?で数かどうかを確認してから比較します
(define eqan?
(lambda (a1 a2)
(cond ((and (number? a1) (number? a2)) (o= a1 a2))
((or (number? a1) (number? a2)) #f)
(else (eq? a1 a2)))))
1かどうかを判定するone?をを定義して、rempickを書き直すとこの章は終わりです
(define one?
(lambda (n)
(cond
(else (o= n 1)))))
なんすかねこれは
どうやったらもっと簡単に、この関数を1行で書けるかどうか考えてみましょう。
ていうかなんで(cond (elseなんて書いてるのかそっちのほうがわかりません
関数は必ずcondで始める、みたいな決まりでもあるんでしょうか
第0の戒律?
(define one?
(lambda (n)
(o= n 1)))