計算機程序的構造和解釋 練習題2.76

帶有顯式分派的通用性操作

在加入一個新類型時,需要添加新類型的構造過程、選擇過程、各自通用操作過程,另外還需要在通用操作過程中加入數據標識的判斷,根據數據標識執行相應的數據類型過程。
而如果需要添加新操作,則需要在每一種類型裏面添加各自的新的操作,還需要添加新操作的通用過程。
拿書中複數的實現舉例添加新類型需要修改的編碼。

#lang racket
//加入新類型的構造過程和選擇過程
(define (real-part-polar z)
  (* (magnitude-polar z) (cos (angle-polar z))))
(define (imag0part-polar z)
  (* (magnitude-polar z) (sin (angle-polar z))))

(define (magintude-polar z) (car z))
(define (angle-polar z) (cdr z))
(define (make-from-real-imag-polar x y)
  (attach-tag 'polar 
              (cons (sqrt (+ (square x) (square y)))
                    (atan y x))))
(define (make-from-mag-ang-polar r a)
  (attach-tag 'polar (cons r a)))
//加入標識判斷
(define (reak-part z)
  (cond ((rectangular? z)
         (real-part-rectangular (contents z)))
        ((polar? z)
         (real-part-polar (contents z)))
        (else (error "Unknown type -- REAL-PART" z))))

不論添加新類型還是新操作都需要修改大量代碼來實現。

數據嚮導風格

在加入一個新類型時,需要添加新類型的過程包就可以,其他地方不需要變動。

#lang racket

(define (install-polar-package)
  (define (magnitude z) (car z))
  (define (angle z) (cdr z))
  (define (make-from-mag-ang r a) (cons r a))
  (define (real-part z)
    (* (magnitude z) (cos (angle z))))
  (define (imag-part z)
    (* (magnitude z) (sin (angle z))))
  (define (make-from-real-imag x y)
    (cons (sqrt (+ (square x) (square y)))
          (atan y x)))
  (define (tag x) (attach-tag 'polar x))
  (put 'real-part '(polar) real-part)
  (put 'imag-part '(polar) imag-part)
  (put 'magnitude '(polar) magnitude)
  (put 'angle '(polar) angle)
  (put 'make-from-real-imag '(polar) 
       (lambda (x y) (tag (make-from-real-imag x y))))
  (put make-from-mag-ang '(polar) 
       (lambda (r a) (tag (make-from-mag-ang r a))))
  'done)

如果添加新操作,也可以添加一個安裝包,這個安裝包裏面包含每一種類型對應新操作的過程,比如下面這種方式。

(define (install-newop-package)
  (define (newop-rectangular z)
    (car z))
  (define (newop-polar z)
    (car  z))
  (put 'newop '(rectangular) newop-rectangular)
  (put 'newop '(polar) newop-polar))

(define (newop z) (apply-generic 'newop z))

這種方式有操作信息表,比較靈活,不管是添加新類型或者新操作,只要操作“操作信息表”就可以。

消息傳遞的風格

在加入一個新類型時,需要添加新類型的構造程序就可以,其他地方不需要變動。

(define (make-from-mag-ang r a)
   (define (dispatch op)
    (cond ((eq? op 'real-part) (* r (cos a)))
          ((eq? op 'imag-part) (* r (sin a)))
          ((eq? op 'magnitude) r)
          ((eq? op 'angle) a)
          (else
           (error "Unknown op -- MAKE-FROM-MAG-ANG" op))))
  dispatch)

如果添加新操作,則需要每一個構造過程加入新的操作函數。

(define (make-from-mag-ang r a)
   (define (dispatch op)
    (cond ((eq? op 'real-part) (* r (cos a)))
          ((eq? op 'imag-part) (* r (sin a)))
          ((eq? op 'magnitude) r)
          ((eq? op 'angle) a)
          ((eq? op 'newop) (square r))
          (else
           (error "Unknown op -- MAKE-FROM-MAG-ANG" op))))
  dispatch)

消息傳遞的風格,不需要過多的選擇函數,代碼量比較小,但是添加新操作比較麻煩,每種都需要添加。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章