灯下 登录
计算机科学 / SICP / 2.5.2 Combining Data of Different Types

Exercise 2.81 · 习题

Exercise 2.81: Louis Reasoner has noticed that
apply-generic may try to coerce the arguments to each other’s type even
if they already have the same type. Therefore, he reasons, we need to put
procedures in the coercion table to
coerce arguments of each type to
their own type. For example, in addition to the
scheme-number->complex coercion shown above, he would do:

(define (scheme-number->scheme-number n) n)
(define (complex->complex z) z)

(put-coercion 'scheme-number 'scheme-number
scheme-number->scheme-number)

(put-coercion 'complex 'complex
complex->complex)

With Louis’s coercion procedures installed, what happens if
apply-generic is called with two arguments of type scheme-number
or two arguments of type complex for an operation that is not found in
the table for those types? For example, assume that we’ve defined a generic
exponentiation operation:

(define (exp x y)
(apply-generic 'exp x y))

and have put a procedure for exponentiation in the Scheme-number
package but not in any other package:

;; following added to Scheme-number package
(put 'exp
'(scheme-number scheme-number)
(lambda (x y)
(tag (expt x y))))
; using primitive expt

What happens if we call exp with two complex numbers as arguments?

Is Louis correct that something had to be done about coercion with arguments of
the same type, or does apply-generic work correctly as is?

Modify apply-generic so that it doesn’t try coercion if the two

arguments have the same type.

练习 2.81:Louis Reasoner 注意到,apply-generic 可能会尝试将参数强制转换为彼此的类型,即使它们已经具有相同的类型。因此,他认为我们需要在强制转换表中放入一些过程,将每种类型的参数强制转换为其自身类型。例如,除了上面所示的 scheme-number->complex 强制转换之外,他还会这样做:

(define (scheme-number->scheme-number n) n)
(define (complex->complex z) z)

(put-coercion 'scheme-number 'scheme-number
scheme-number->scheme-number)

(put-coercion 'complex 'complex
complex->complex)

安装了 Louis 的强制转换过程之后,如果 apply-generic 以两个类型为 scheme-number 的参数或两个类型为 complex 的参数调用某个在表中找不到的操作,会发生什么?例如,假设我们定义了一个通用的求幂操作:

(define (exp x y)
(apply-generic 'exp x y))

并在 Scheme-number 包中放入了一个求幂过程,但其他包中没有:

;; following added to Scheme-number package
(put 'exp
'(scheme-number scheme-number)
(lambda (x y)
(tag (expt x y))))
; using primitive expt

如果我们以两个复数为参数调用 exp,会发生什么?

Louis 认为对于相同类型的参数确实需要做些处理,还是说 apply-generic 本来就能正确工作?

修改 apply-generic,使其在两个参数类型相同时不尝试强制转换。

Racket #lang sicp
(define (scheme-number->scheme-number n) n)
(define (complex->complex z) z)

(put-coercion 'scheme-number 'scheme-number
 scheme-number->scheme-number)

(put-coercion 'complex 'complex
 complex->complex)