;;a
apply-generic calls itself recursively on coerced types, so it goes into infinite recursion.
;;b
Louis's code can't work. apply-generic just works as it is.
;;c
(define(apply-generic op . args)(define(no-method type-tags)(error "No method for these types"(list op type-tags)))(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(equal? type1 type2)(no-method type-tags)(let((t1->t2 (get-coercion type1 type2))(t2->t1 (get-coercion type2 type1))(a1 (car args))(a2 (cadr args)))(cond(t1->t2
(apply-generic op (t1->t2 a1) a2))(t2->t1
(apply-generic op a1 (t2->t1 a2)))(else(no-method type-tags))))))(no-method type-tags))))))
Then the program will exit with an error when apply-generic is called for the first time (it attempts to apply type-tag to untagged scheme primitives). However, if (type-tag) is able to handle scheme primitives like so:
Then the program will loop recursively forever coercing scheme numbers into themselves and then calling apply-generic on the coerced data, as meteorgan says.
For 87b, I think that Louis is correct in the sense that "something had to be done about coercion with arguments of the same type" because even though (apply-generic) will exit with an error if no coercion is found, that doesn't stop our users from adding same-type coercion operators to our table (Louis already did it once). I do agree with meteorgan, that although something had to be done, the thing that Louis did is the wrong thing. I think apply-generic would be "more correct" if it was modified to exit with an error BEFORE attempting any same-type coercions. We could also add code to the `put` procedure which would make it exit with an error if a user attempted to `put` in a same-type coercion, but that would be extremely difficult (maybe impossible) and also adversely affect the expressiveness of our language.
atomik's correction to part a is wrong, it does infinite loop. One, the question is asking about complex numbers, not scheme numbers: "What happens if we call exp with two complex numbers as arguments?". Two, the claim about the error due to an "untagged scheme primitive" is irrelevant - if the first `type-tag` is installed in the system, then users must tag their numbers when calling generic functions. If it's the second `type-tag`, users don't have to tag their numbers. Simple as that.
atomik
meteorgan's answer to 87a is partially correct.
For scheme-numbers, it depends on which implementation of `(type-tag)` is being used. If (type-tag) is defined like so:
(define (type-tag datum) (if (pair? datum) (car datum) (error "Bad tagged datum")))
Then the program will exit with an error when apply-generic is called for the first time (it attempts to apply type-tag to untagged scheme primitives). However, if (type-tag) is able to handle scheme primitives like so:
(define (type-tag datum) (cond ((number? datum) 'scheme-number) ((pair? datum) (car datum)) (else (error "Bad tagged datum"))))
Then the program will loop recursively forever coercing scheme numbers into themselves and then calling apply-generic on the coerced data, as meteorgan says.
For 87b, I think that Louis is correct in the sense that "something had to be done about coercion with arguments of the same type" because even though (apply-generic) will exit with an error if no coercion is found, that doesn't stop our users from adding same-type coercion operators to our table (Louis already did it once). I do agree with meteorgan, that although something had to be done, the thing that Louis did is the wrong thing. I think apply-generic would be "more correct" if it was modified to exit with an error BEFORE attempting any same-type coercions. We could also add code to the `put` procedure which would make it exit with an error if a user attempted to `put` in a same-type coercion, but that would be extremely difficult (maybe impossible) and also adversely affect the expressiveness of our language.
Ergomaniac
atomik's correction to part a is wrong, it does infinite loop. One, the question is asking about complex numbers, not scheme numbers: "What happens if we call exp with two complex numbers as arguments?". Two, the claim about the error due to an "untagged scheme primitive" is irrelevant - if the first `type-tag` is installed in the system, then users must tag their numbers when calling generic functions. If it's the second `type-tag`, users don't have to tag their numbers. Simple as that.