kb84tkhrのブログ

何を書こうか考え中です あ、あと組織とは関係ないってやつです 個人的なやつ

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-adderfull-subberがまったく同じになりました
これはちょっと意外
でも考えてみるとありそうな話ではある