Reasoned Schemer (31) 引き算 続き
(Reasoned Schemerから少し離れてしまっている)
でどっちでやろうか
full-adderとかの方が自分にとって新しいのでそっちで書いてみよう
全部反対にするだけだろうし
と思った私があさはかでした
subber
というのは変な名前ですがsubtructor
では長いのでご容赦
(define (half-subber x y)
(values (bit-xor x y) (if (and (= x 0) (= y 1)) 1 0)))
(define (full-subber b x y)
(let*-values (((w xy) (half-subber x y))
((r wz) (half-subber w b))
((c) (bit-xor xy wz)))
(values r c)))
(define (subber b n m)
(cond
((and (= b 0) (null? n) (null? m) '()))
((null? n) #f)
((and (= b 0) (null? m)) n)
((and (= b 1) (null? m)) (subber 0 n '(1)))
((and (= b 0) (equal? n '(1)) (equal? m '(1))) '())
((and (= b 1) (equal? n '(1)) (equal? m '(1))) #f)
(else (gen-subber b n m))))
(define (gen-subber b n m)
(let*-values
(((c e) (full-subber b (car n) (car m)))
((z) (subber e (cdr n) (cdr m))))
(and z (cons c z))))
(define (trim-zero n)
(and n
(let ((w (member 1 (reverse n))))
(if w (reverse w) '()))))
(define (sub n m)
(trim-zero (subber 0 n m)))
負の数がないというのが痛い
とりあえず答えが負になるところは#f
を返すようにしましたが
おかげで場合分けはわけわかんなくなるわ
#f
を再帰呼び出しの元まで伝えなきゃいけないわ
(そういえば例外の使い方知らない)
上位ビットにゼロが残ることがあるので取らないといけないわで
2の補数でやったほうが楽だったかもしれない
楽そうだからこっちでやったわけじゃないけど
とはいえ、だから関係プログラミングのほうが楽、という感じではないかな
答えがない、というのを自然に表せるというのは利点だと思うけど
関数型でもあらためて考え直せばもっとシンプルに書けそうな気がしないでもない
ところでfull-adder
とfull-subber
がまったく同じになりました
これはちょっと意外
でも考えてみるとありそうな話ではある