SICPを読む(88) 問題 2.77-2.80 汎用演算システム
汎用演算システムに入ります。パッケージの定義が単調過ぎてあんまり面白みが無い。
問題 2.77
'(complex rectanglar 3 . 4)
に対して、
- (magnitude z)を評価したら、ダメだった。complexパッケージに、アクセサの手続きを加えたら、うまく動いた。何故か?
- apply-genericは何回呼ばれるか?
という問題。
complexパッケージは、手続きを直交座標、極座標パッケージに操作を委譲してる形になってるのがポイント。
- apply-genericは、とりあえず、car部にあるcomplexタグと、magnitudeを探しにいくので、エラーとなる。
- 手続きを追うと
- (magnitude '(complex rectanglar 3 . 4))
- (apply-generic 'magnitude '(complex rectanglar 3 . 4))
- (magnitude '(rectanglar 3 . 4))
- (apply-generic 'magnitude '(rectanglar 3 . 4))
- magnitudeパッケージの、rectanglarが呼ばれる。
- complex,rectanglarを見に行くので、2回。
難しくはないとおもう。
traceしてみると、
(magnitude (make-complex-from-real-imag 3 4)) |(apply-generic magnitude (complex rectanglar 3 . 4)) |(apply-generic magnitude (rectanglar 3 . 4)) |5 5
正解!
問題 2.78
ちょっと迷ったけど、クリア!
(define (attach-tag type-tag contents) (if (eq? type-tag 'scheme-number) contents (cons type-tag contents))) (define (type-tag datum) (cond ((number? datum) 'scheme-number) ((pair? datum) (car datum)) (else (error "Bad tagged datum -- TYPE-TAG" datum)))) (define (contents datum) (cond ((number? datum) datum) ((pair? datum) (cdr datum)) (else (error "Bad tagged datum -- CONTENTS" datum))))
テスト。
(add (make-scheme-numbr 2) (make-scheme-numbr 3)) (- (make-scheme-numbr 2) (make-scheme-numbr 1)) (mul 3 4)
どっちでも動く。
ちょっとしたこと
整数と小数の比較。
(eq? 0 0.0) ; #f (eqv? 0 0.0) ; #f (equal? 0 0.0) ; #f
全部#fになった。型を意識したほうが良いらしい。
Cだと、
printf("%s\n", 0 == 0.0 ? "いっしょ" : "ちがう"); /* いっしょ */
いっしょになる。
JSだと、
js> 0 == 0.0 ? "いっしょ" : "ちがう" いっしょ
Rubyも。
irb(main):002:0> 0 == 0.0 => true
どうやら、Schemeは特殊っぽい。
問題 2.79,2.80
面倒なので、回答はcomplexだけ。
(put 'equ? '(complex complex) (lambda (x y) (and (eq? (real-part x) (real-part y)) (eq? (imag-part x) (imag-part y))))) (put '=zero? '(complex) (lambda (x) (and (zero? (real-part x)) (zero? (imag-part x)))))
まとめ
解説が長い。ちょっと飽き気味。