乐正

Actions speak louder than words.

Sicp-ex2-81

问题

uis Reasoner 注意到,甚至在两个参数的类型实际相同的情况下,apply-generic也可能 试图去做参数间的类型强制。由此,他推论说,需要在强制表格中加入一些过程,以将每个 类型的参数“强制”到它们自己的类型。例如,除了上面给出的scheme-number->complex强 制之外,他觉得应该有:

1
2
3
4
5
(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)

a) 如果安装了Louis的强制过程,如果在调用apply-generic时各参数的类型都为scheme-number 或者类型都为complex,而在表格中又找不到相应的操作,这时会出现什么情况?例如, 假定我们定义了一个通用型的求幂运算:

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

并在scheme数值包里放了一个求幂过程,但其它程序包里没有:

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

如果对两个复数调用exp会出现什么情况?

b) Louis真的纠正了有关同样类型参数的强制问题吗?apply-generic还能像原来那样正 确工作吗?

c) 请修改apply-generic,使之不会去试着强制两个同样类型的参数。

解答

a) 问中,当对复数调用exp时,会发生超过最大递归调用栈的情况。因为,在apply-generic 中会因为找到了第一个参数到第二个参数的强制过程,继而继续调用apply-generic,如 此反复。

b) 从a)问的回答中可以看到,apply-generic已经不能在上述情况下正常的抛出异常了。 Loius没有纠正有关同样类型参数强制的问题。

练习2.81 (ex2-81.scm) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
(define (apply-generic op . args)
  (let ((type-tags (map type-tag args)))
    (let ((proc (get op type-tags)))
      (if proc
          (apply proc (map contents args))
          (if (= (length args) 2)
              (let ((type1 (car type-tags))
                    (type2 (cadr type-tags))
                    (a1 (car args))
                    (a2 (cadr args)))
                (if (not (eq? typ1 type2))
                    (let ((t1->t2 (get-coercion type1 type2))
                          (t2->t1 (get-coercion type2 type1)))
                      (cond (t1->t2
                              (apply-generic (t1->t2 t1) t2))
                            (t2->t1
                              (apply-generic t1 (t2->t1 t2)))
                            (else
                              (error "No method for these types"
                                     (list op type-tags)))))
                    (error "No method for these types"
                           (list op type-tags))))
              (error "No method for these types"
                     (list op type-tags)))))))

draft

« sicp-ex2-80 sicp-ex2-82 »

Comments