Exercise 2.77. Louis Reasoner tries to evaluate the expression (magnitude z) where z is the object shown in figure 2.24. To his surprise, instead of the answer 5 he gets an error message from apply-generic, saying there is no method for the operation magnitude on the types (complex). He shows this interaction to Alyssa P. Hacker, who says ‘‘The problem is that the complex-number selectors were never defined for complex numbers, just for polar and rectangular numbers. All you have to do to make this work is add the following to the complex package:‘’
(put 'real-part '(complex) real-part)
(put 'imag-part '(complex) imag-part)
(put 'magnitude '(complex) magnitude)
(put 'angle '(complex) angle)
Describe in detail why this works. As an example, trace through all the procedures called in evaluating the expression (magnitude z) where z is the object shown in figure 2.24. In particular, how many times is apply-generic invoked? What procedure is dispatched to in each case?
要理解这一题,需要理解两点:
- data-directed 是如何工作的?
- 当前的表中是什么样子?
data-directed 如何工作
data-directed 实际是 type-directed。对于一种数据,我们的操作可以自动地识别这种数据的类型,然后分配相应的过程来处理。
在这一节中的类型以及相应的过程(只是部分过程)如下表
========== ============= ======= =========== ======= ============= ======== ========= ============================= =================== =================
(rectangular) (polar) rectangular polar scheme-number rational (complex) (scheme-number scheme-number) (rational rational) (complex complex)
---------- ------------- ------- ----------- ------- ------------- -------- --------- ----------------------------- ------------------- -----------------
add X + add-rat add-complex
---------- ------------- ------- ----------- ------- ------------- -------- --------- ----------------------------- ------------------- -----------------
sub X - sub-rat sub-complex
---------- ------------- ------- ----------- ------- ------------- -------- --------- ----------------------------- ------------------- -----------------
mul X * mul-rat mul-complex
---------- ------------- ------- ----------- ------- ------------- -------- --------- ----------------------------- ------------------- -----------------
div X / div-rat div-complex
---------- ------------- ------- ----------- ------- ------------- -------- --------- ----------------------------- ------------------- -----------------
make X (lambda (x) (tag x)) make-rat X
---------- ------------- ------- ----------- ------- ------------- -------- --------- ----------------------------- ------------------- -----------------
real-part real1 real2
---------- ------------- ------- ----------- ------- ------------- -------- --------- ----------------------------- ------------------- -----------------
imag-part imag1 imag2
---------- ------------- ------- ----------- ------- ------------- -------- --------- ----------------------------- ------------------- -----------------
magnitude mag1 mag2 X
---------- ------------- ------- ----------- ------- ------------- -------- --------- ----------------------------- ------------------- -----------------
make-from* real-imag mag-ang
---------- ------------- ------- ----------- ------- ------------- -------- --------- ----------------------------- ------------------- -----------------
Angle angle1 angle2
========== ============= ======= =========== ======= ============= ======== ========= ============================= =================== =================
如果对 complex 使用 magnitude,那么程序将会去表中查找 magnitude 行,(complex) 列去查看是否有过程。因为我们的 magnitude 只针对 rectangular 和 polar 有相应过程,所以解释器报错了。
所以,当我们添加了
(put 'magnitude '(complex) magnitude)
了之后,我们就在 magnitude 行,(complex) 列安装 magnitude 过程。因为 magnitude 过程是定义为
(define (magnitude z) (apply-generic 'magnitude z))
所以,计算 (magnitude (complex polar 3 . 34)) 则回调用两次 apply-generic,第一次剥掉了 complex 标签,第二次剥掉了 polar 标签。