SICP 読み (78) 2.5.3 例: 記号代数
現実トウヒな成果を。
問題 2.88
多項式な減算オペレータの定義。原文のヒントによれば
define a generic negation operation
とある。符号を反転させて加算すれば良いのな、と。とりあえず試験をいっこデッチ上げておいて実装検討。
#!/usr/bin/env gosh (use test.unit) (require "2.5.3") (define-test-suite "2.5.3" ("2-88" (setup (lambda () (install-scheme-number-package) (install-polynomial-package))) ("first (1x - 1x = 0)" (assert-true (=zero? (sub (make-polynomial 'x '((1 1))) (make-polynomial 'x '((1 1)))))) ) ) -- 以下略 --
えーと、こんな感じ??
(put 'sub '(polynomial polynomial) (lambda (p1 p2) (tag (add-poly p1 (neg p2)))))
neg という手続きも必要。
(put 'neg '(polynomial) (lambda (p) (tag (neg-poly p))))
neg-poly は
(make-poly (variable p) (neg-terms (term-list p)))
で良い?
neg-terms は引数なリストの coeff を順に - すれば良いのかな??
面倒なので neg-poly 関連の手続きの下書きを以下に。
(define (neg-poly p) (make-poly (variable p) (neg-terms (term-list p)))) (define (neg-terms L) (let f ((L L) (ret '())) (if (null? L) ret (f (cdr L) (cons (list (order (car L)) (- (coeff (car L)))) ret)))))
なんかごちゃごちゃしてるなぁ。盛り込んで試験してみる。
試験
で、上記を盛り込んで試験してみたのですが、失敗。以下のようにしたら通った。
(put 'sub '(polynomial polynomial) (lambda (p1 p2) (tag (add-poly p1 (neg-poly p2)))))
汎用符号反転演算はドコに行ったんだ。これじゃ駄目だよ。
でも、符号の反転を汎用にするとしたら、sub という手続きに盛り込む形は取るべきではないのかなぁ。neg を使えば add を使って減算できますよ、みたいな??
自分勝手な理解ですが、そうする事に。なので
- sub は定義しない
- neg のみ定義
で試験は以下になりますか。
("2-88" (setup (lambda () (install-scheme-number-package) (install-polynomial-package))) ("first (1x - 1x = 0)" (assert-true (=zero? (add (make-polynomial 'x '((1 1))) (neg (make-polynomial 'x '((1 1))))))) ) )
neg 手続きの定義は上記と同じですが、トップレベルで以下の記述が必要。
(define (neg x) (apply-generic 'neg x))
多項式と言いつつ単項の試験しかしてないので、試験の追加が必要。あ、0 に対して neg しちゃ駄目だな。判定は neg-terms ん中で、でしょうか。って 0 だったら 0 を返してるようにも見えるな。どちらにしても試験が足りてない。
で、以下の試験を追加してみると NG。
("2nd (1x - 0 = 1x)" (let ((p (make-polynomial 'x '((1 1))))) (assert-equal p (add p (neg (make-polynomial 'x '()))))) ) ("3rd (1x - 0x = 1x" (let ((p1 (make-polynomial 'x '((1 1)))) (p0 (make-polynomial 'x '((1 0))))) (assert-equal p1 (add p1 (neg p0)))) ) ("4th polynomial neg" (let ((p1 (make-polynomial 'x '((3 1) (2 2) (1 3) (0 4)))) (p2 (make-polynomial 'x '((3 -1) (2 -2) (1 -3) (0 -4))))) (assert-equal p1 (neg p2)) (assert-equal p2 (neg p1))) )
最後の多項式なソレが逆になってるし。
mul-term-by-all-terms 手続きをパクッて以下のように修正。
(define (neg-terms L) (if (empty-termlist? L) (the-empty-termlist) (let ((t (first-term L))) (adjoin-term (make-term (order t) (- (coeff t))) (neg-terms (rest-terms L))))) )
てきとーにやってるのバレバレだなぁ。自分ででっち上げずに、まず周囲を見なさい、が教訓か。肝に命じながらすぐに忘れてしまいます。(駄目
追記
しかし、negation って辞書引いたら「否定」なんだけど、和訳な本では「符号反転」になっています。うーん。