Scheme手習い 第4章 数遊び(その1)
この章では数の扱いを習います。元々Scheme(あるいはR5RS)として算術関数は定義されていますが、それを改めて自前で再帰的に定義します。
ノート:
一応、各々の数字がアトムか否かを確認する。
> (atom? 14) #t > (atom? -3) #t > (atom? 3.1415) #t >
add1、sub1
add1の定義は脚注に提示されているが、本書ではadd1は組み込み関数として扱われている。
> (let ((n 67)) (add1 n)) 68 > (add1 67) 68 >
引数が数のときは「ここで、nは67です」と言う必要はありません。(because we don't need to say "where n is 67" when the argument is a number.)
正確には分からないが、quoteする必要がないと言う事と関連しているのかも知れない。
sub1も同様に組み込み関数として扱われている。
> (let ((n 5)) (sub1 n)) 4 > (sub1 0) -1 >
本書では負の数は扱わないと言う事なので、(sub1 0)の答えは無いと書いてあるが、実際の実装系では当然-1と言う答えになる。
zero?
zero?はR5RSで定義されている。
> (zero? 0) #t > (zero? 1492) #f >
⊕
本書ではadd1、sub1、zero?を用いて自前の加算演算関数を定義する。元々ある加算演算関数と重複してしまわない様に本では白抜きの+を使用しているが、UTFの文字表から適当な字が見つからないので、⊕で代用する。DrRacketではUTFの文字もちゃんと認識してくれる。
m+nの定義:
- mが0であれば、n
- そうでなければ、n + (m-1)に1を加えた数
はてなのpre記法では表示出来ないようなので、ここでは全角の+で表記しておく。DrRacketのプログラム上でも全角の+は使える、本物の+と見分けが付きにくかったので、自分のプログラム上では⊕を使用している。
> (+ 46 12) 58 >
⊖
同様に減算関数。
m-nの定義
- mが0であれば、n
- そうでなければ、n - (m-1)から1引いた数
同様にここでは全角のーで表記しておく。
> (ー 14 3) 11 > (ー 17 9) 8 > (ー 18 25) -7 >
タップ(タプル)
数のリストのことをタップ(あるいはタプル)と呼びましょう。(Yes: tup is short for tupple.)
「あるいは」と書いてあるが、タップはタプルの短縮形としている。
addtup
タップに含まれる数の合計を求める関数。
addtupの定義:
- 数だけからなるリストtupに適用し、「各要素の合計」を意味する。
- tupが空であれば、0
- 空でなければ、tupの先頭要素の数とtupの残りの要素にaddtupを適用した数の合計
この定義をちゃんとプログラムとして表示すると:
(define addtup (lambda (tup) (cond ((null? tup) 0) (else (⊕ (car tup) (addtup (cdr tup)))))))
評価してみる。
> (addtup '(3 5 2 8)) 18 > (addtup '(15 6 7 12 3)) 43 >
×
これは*と見間違える事はないので全角の×を使う。
> (× 5 3) 15 > (× 13 4) 52 > (× 12 3) 36 >
第5の戒律:…行を終えるときに常に値として0を用うべし。(always use 0 for the value of the terminating line,)…
「行を終えるとき」ではなく「再帰を終える行に於いて」と解釈する。
tup+
最初の定義で評価してみる。
> (tup+ '(3 6 9 11 4) '(8 5 2 0 7)) (11 11 11 11 11) > (tup+ '(2 3) '(4 6)) (6 9) > (tup+ '(3 7) '(4 6)) (7 13) >
この定義では二つのタップの要素数が同じじゃないとエラーを起こす。
> (tup+ '(3 7) '(4 6 8 1)) . . mcar: expects argument of type <mutable-pair>; given () >
新しい定義を評価してみる。
> (tup+ '(3 7) '(4 6 8 1)) (7 13 8 1) >