Chapter 2
2.1 Exercise 2.1
2.2 Exercise 2.2
2.3 Exercise 2.3
2.4 Exercise 2.4
2.5 Exercise 2.5
2.6 Exercise 2.6
2.7 Exercise 2.7
2.8 Exercise 2.8
2.9 Exercise 2.9
2.10 Exercise 2.10
2.11 Exercise 2.11
2.12 Exercise 2.12
2.13 Exercise 2.13
2.14 Exercise 2.14
2.15 Exercise 2.15
2.16 Exercise 2.16
2.17 Exercise 2.17
2.18 Exercise 2.18
2.19 Exercise 2.19
2.20 Exercise 2.20
2.21 Exercise 2.21
2.22 Exercise 2.22
2.23 Exercise 2.23
2.24 Exercise 2.24
2.25 Exercise 2.25
2.26 Exercise 2.26
2.27 Exercise 2.27
2.28 Exercise 2.28
2.29 Exercise 2.29
2.30 Exercise 2.30
2.31 Exercise 2.31
2.32 Exercise 2.32
2.33 Exercise 2.33
2.34 Exercise 2.34
2.35 Exercise 2.35
2.36 Exercise 2.36
2.37 Exercise 2.37
2.38 Exercise 2.38
2.39 Exercise 2.39
2.40 Exercise 2.40
2.41 Exercise 2.41
2.42 Exercise 2.42
2.43 Exercise 2.43
2.44 Exercise 2.44
2.45 Exercise 2.45
2.46 Exercise 2.46
2.47 Exercise 2.47
2.48 Exercise 2.48
2.49 Exercise 2.49
2.50 Exercise 2.50
2.51 Exercise 2.51
2.52 Exercise 2.52
2.53 Exercise 2.53
2.54 Exercise 2.54
2.55 Exercise 2.55
2.56 Exercise 2.56
2.57 Exercise 2.57
2.58 Exercise 2.58
2.59 Exercise 2.59
2.60 Exercise 2.60
2.61 Exercise 2.61
2.62 Exercise 2.62
2.63 Exercise 2.63
2.64 Exercise 2.64
2.65 Exercise 2.65
2.66 Exercise 2.66
2.67 Exercise 2.67
2.68 Exercise 2.68
2.69 Exercise 2.69
2.70 Exercise 2.70
2.71 Exercise 2.71
2.72 Exercise 2.72
2.73 Exercise 2.73
2.74 Exercise 2.74
2.75 Exercise 2.75
2.76 Exercise 2.76
2.77 Exercise 2.77
2.78 Exercise 2.78
2.79 Exercise 2.79
2.80 Exercise 2.80
2.81 Exercise 2.81
2.82 Exercise 2.82
2.83 Exercise 2.83
2.84 Exercise 2.84
2.85 Exercise 2.85
2.86 Exercise 2.86
2.87 Exercise 2.87
2.88 Exercise 2.88
2.89 Exercise 2.89
2.90 Exercise 2.90
2.91 Exercise 2.91
2.92 Exercise 2.92
2.93 Exercise 2.93
2.94 Exercise 2.94
2.95 Exercise 2.95
2.96 Exercise 2.96
2.97 Exercise 2.97

2.81 Exercise 2.81

Louis Reasoner wants to install coercions from types to themselves, because apply-generic may try to do this is a procedure isn’t found. Of course, the only reason this would happen is if an operation on the two types couldn’t be found in the first place, and coercing a type to itself won’t change that (this is Loose Reasoner, after all), but let’s play along anyway.

So suppose we have a new procedure for exponentiation only defined on Scheme numbers, created like this:

(define (exp x y) (apply-generic 'exp x y))
 
(put 'exp '(scheme-number scheme-number)
     (lambda (x y) (tag (expt x y))))

If we try to call this procedure on two complex numbers, apply-generic won’t be able to find a procedure using get, and so will attempt to coerce the complex numbers to complex numbers and see if there is a procedure then. But looking at how apply-generic is defined, we can see that we don’t have to write these self-coercions:

(let ((t1->t2 (get-coercion type1 type2))
      (t2->t1 (get-coercion type2 type1)))
  (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)))))

If we don’t install self-coercions into the table, neither t1->t2 nor t2->t1 will exist, and the call to exp will yield and error as expected. However, if we do install the self-coercions, apply-generic will be called again with one "coerced" argument.

But of course, the next time through apply-generic, the same thing will happen – a suitable procedure won’t be found, and so the first argument will be "coerced" and apply-generic will be called again. Installing these procedures will make apply-generic nonterminating whenever a procedure for two arguments of the same type isn’t found. This is clearly wrong.

We could modify apply-generic to not attempt to look up coercions if the types are the same. It might look something like this:

(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 (and (= (length args) 2)
                   (not (eq? (car type-tags)
                             (cadr type-tags))))
              ;; ...
              (error "No method for these types"
                     (list op type-tags)))))))

You could also check if the types are equal inside the if (conveniently after you have names for them), but I prefer this a little bit because it doesn’t increase the number of exit points in the procedure (that is, I would need to add another call to error).