2.84¶
; Using the raise operation of Exercise 2.83, modify the apply-generic procedure so ; that it coerces its arguments to have the same type by the method of successive ; raising, as discussed in this section. You will need to devise a way to test which ; of two types is higher in the tower. Do this in a manner that is “compatible” with ; the rest of the system and will not lead to problems in adding new levels to the ; tower. ; Source: [https://wizardbook.wordpress.com/2010/12/08/exercise-2-84/](https://wizardbook.wordpress.com/2010/12/08/exercise-2-84/) (define (apply-generic op . args) ; find the highest type level of a list of arguments (define (highest-type-level args) (if (null? args) 0 (let ((level (type-level (car args))) (highest (highest-type-level (cdr args)))) (if (> level highest) level highest)))) ; raise arg to the same level as target-type-level (define (raise-to arg target-type-level) (define (raise-iter current-arg) (let ((arg-level (type-level current-arg))) (cond ((= arg-level target-type-level) current-arg) ((< arg-level target-type-level) (raise-iter (apply-generic 'raise current-arg))) (else (error "Cannot raise argument to a lower type target" arg target-type-level))))) (raise-iter arg)) ; raise all args to a common type (the highest in the tower of types) ; and apply the operator to them (define (apply-with-raised-types args) (let ((target-type-level (highest-type-level args))) (apply apply-generic op (map (lambda (arg) (raise-to arg target-type-level)) args)))) (let* ((type-tags (map type-tag args)) (proc (get op type-tags))) (if proc (apply proc (map contents args)) (apply-with-raised-types args)))) ; This uses a new top-level generic procedure to find the level of the number type ; and a new procedure for each of the number types. (define (type-level z) (apply-generic 'type-level z)) (put 'type-level '(integer) (lambda (x) 1)) (put 'type-level '(rational) (lambda (x) 2)) (put 'type-level '(real) (lambda (x) 3)) (put 'type-level '(complex) (lambda (x) 4))