SICP Practice

Practice 2.81

(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)))
	              (let ((t1->t2 (get-coercion type1 type2))
	                    (t2->t1 (get-coercion type2 typw1)))
	                (cond (t1->t2
	                        (apply-generic op (t1->t2 a1) a2))
	                      (t2->t1
	                        (apply-generic op a1 (t2->t1 a2)))
	                      (else 
	                        (error "No method for these types"
	                          (list op type-tags))))))
	            (error "No method for these types"
	                 (list op type-tags)))))))

when invoking (apply-generic ‘exp x y), both x y are scheme-number, let proc equal (get ‘exp ‘(scheme-number scheme-number)), it will work well, if invoking (apply-generic ‘exp x y), both x and y are complex, (get ‘exp ‘(complex complex)) is not in table,it will coerce type1 to type2 or type2 to type1, since both type1 and type2 are complex, it will call (apply-generic op a1 a2). That is just the start status (apply-generic op.args). So it’s a infinite loop. It will not get the correct anwser.

Modified apply-generic

(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? type1 type2))
		              (let ((t1->t2 (get-coercion type1 type2))
		                    (t2->t1 (get-coercion type2 typw1)))
		                (cond (t1->t2
		                        (apply-generic op (t1->t2 a1) a2))
		                      (t2->t1
		                        (apply-generic op a1 (t2->t1 a2)))
		                      (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)))))))