問題2-75〜76

put-get-genと問題2-74は時間をしっかりと作ってから取り組んでみようと思ってますので、次のメッセージパッシングの問題に進みます。
演算や型の定義をputを使って登録しつつ、getを用いて適用していくというやりかたではなく、型ごとに、その型で使われる手続きを定義するというのがメッセージパッシングです。それぞれの型ごとに定義された演算メソッドを呼び出すような、そんな感じでしょうか。

(define (make-from-real-imag x y)
  (define (dispatch op)
    (cond ((eq? op 'real-part) x)
          ((eq? op 'imag-part) y)
          ((eq? op 'magnitude)
           (sqrt (+ (square x) (square y))))
          ((eq? op 'angle) (atan y x))
          (else
           (error "Unknown op" op))))
  dispatch)

(define test-rect (make-from-real-imag 3 1))

(test-rect 'real-part)  ;=>3
(test-rect 'imag-part)  ;=>1
(test-rect 'magnitude)  ;=>3.1622776601683795
(test-rect 'angle)  ;=>0.3217505543966422

(define (make-from-mag-ang x y)
  (define (dispatch op)
    (cond ((eq? op 'real-part)
           (* x (cos y)))
          ((eq? op 'imag-part)
           (* x (sin y)))
          ((eq? op 'magnitude) x)
          ((eq? op 'angle) y)
          (else
           (error "Unknown op" op))))
  dispatch)

(define test-polar (make-from-mag-ang 3 1))

(test-polar 'real-part)  ;=>1.6209069176044193
(test-polar 'imag-part)  ;=>2.5244129544236893
(test-polar 'magnitude)  ;=>3
(test-polar 'angle)  ;=>1

まとめの問題である問題2-76ですが、新しい演算が増えた場合、汎用演算流だと、その演算処理を追加するだけで済みそうですが、データ主導/メッセージパッシングでは、それぞれの型にその演算処理を加えなければなりません。逆に、新しい型が増えた場合は、汎用演算流では、全ての演算手続きに型の振り分け処理を追加しなければなりませんが、データ主導/メッセージパッシングだと、その型に関する処理群を追加してやればいいことになります。
しかし、問題2-73の記号微分書き換えに関するトピックでも見た通り、何を演算要素とし、何を型とするかによって、捉え方が変わってくるとも思うので、このあたりについての視点もしっかりと持ちながら、次節以降の内容に触れていきたいと考えています。