読者です 読者をやめる 読者になる 読者になる

kb84tkhrのブログ

何を書こうか考え中です

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)))

  1. Racket(ていうか普通のschemeでも)ではeq?で数字も比較できます