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.) ; Source: [https://wizardbook.wordpress.com/2010/12/08/exercise-2-82/](https://wizardbook.wordpress.com/2010/12/08/exercise-2-82/) (define (apply-generic op . args) (define (all-coercable? coerce-procs) (not (member #f coerce-procs))) (define (coerce-args coercion-procs args) (map (lambda (coerce-proc arg) (coerce-proc arg)) coercion-procs args)) ; attempt to coerce all args into a common type among the args (define (apply-with-coercion arg-types) ; attempt to coerce all args using each tag-type in turn ; it's a scoped procedure to keep the original arguments (arg-types) for error reporting (define (coerce-types tags) (if (null? tags) ; all targets exhausted (error "No method for these types - APPLY-GENERIC" (list op arg-types)) (let* ((target-type (car tags)) (arg-coercions (map ; get all the coercion procedures from the target (lambda (coerce-from) (if (eq? coerce-from target-type) identity (get-coercion coerce-from target-type))) arg-types))) (if (all-coercable? arg-coercions) ; the target type is valid if all the args can be coerced (apply apply-generic op (coerce-args arg-coercions args)) ; target-type is not valid, so try the next one in the list (coerce-types (cdr tags)))))) ; try the next target type (coerce-types arg-types)) (let* ((type-tags (map type-tag args)) (proc (get op type-tags))) (if proc (apply proc (map contents args)) (apply-with-coercion type-tags))))