Exercise 2.82. Show how to generalize apply-generic to handle coercion in the general case of multiple arguments. One strategy is to attempt to coerce all the arguments to the type of the first argument, then to the type of the second argument, and so on. Give an example of a situation where this strategy (and likewise the two-argument version given above) is not sufficiently general. (Hint: Consider the case where there are some suitable mixed-type operations present in the table that will not be tried.) ———————————————————————————————————————————————————————————————————————— (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)) (let ((coerced-args (get-coerced-args args type-tags))) (if coerced-args (apply apply-generic op coerced-args) (error "No method for these types" (list op type-tags)))))))) (define (get-coerced-args args types) (if (null? types) false (let ((coerced-args (coerce-all-to args (car types))) (if (coerced-args) coerced-args (get-coerced-args args (cdr types))))))) (define (coerce-all-to args type) (if (null? args) '() (let ((rest (coerce-all-to (cdr args) type)) (coercion (get-coercion (type-tag (car args)) type))) (if rest (cond ((eq? (type-tag (car args)) type) (cons (car args) rest)) (coercion (cons (coercion (car args)) rest)) (else false)) false)))) If there is a coercion from type A to B and from A to C, and an operation is defined on (B C) but not on (A C) or (C C), attempting to apply that operation to arguments of type (A C) will coerce the first argument to C and will fail, rather than trying the coercion to B and succeeding.