Friday, June 19, 2009

Section-2.5.2; Ex-2.81-2.86

Ex-2.81
a; It will fall into a recursive loop. Why, here is the reason
 1(define (apply-generic op . args)
2 (let ((type-tags (map type-tag args)))
3 (let ((proc (get op type-tags)))
4 (if proc
5 (apply proc (map contents args))
6 (if (= (length args) 2)
7 (let ((type1 (car type-tags))
8 (type2 (cadr type-tags))
9 (a1 (car args))
10 (a2 (cadr args)))
11 (let ((t1->t2 (get-coercion type1 type2))
12 (t2->t1 (get-coercion type2 type1)))
13 (cond (t1->t2
14 (apply-generic op (t1->t2 a1) a2))
15 (t2->t1
16 (apply-generic op a1 (t2->t1 a2)))
17 (else
18 (error "No method for these types"
19 (list op type-tags))))))
20 (error "No method for these types"
21 (list op type-tags)))))))

(exp x y) ;x and y are complex numbers
(apply-generic 'exp x y)

Now since there is no operation called exp is defined for type (complex complex), proc obtained at line 3 will be nil and we'll come to line 6 in above code. At line 11 t1->t2 will again be x and we'll recursively end up calling (apply-generic 'exp x y) again and will never exit.

b;If proc at line 3 is not nil then there is absolutely no issue. But if its nil then apply-generic will unnecessarily try to do the coercion. So, the conclusion is, it will work as is but will try to do the useless coercion.

c;
(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 (= (length args) 2)
(let ((type1 (car type-tags))
(type2 (cadr type-tags))
(a1 (car args))
(a2 (cadr args)))
(if (eq? type1 type2)
(error "No method for these types"
(list op type-tags))
(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)))))))
(error "No method for these types"
(list op type-tags)))))))

Ex-2.82
This strategy will fail in following situation, let say we call a generic procedure on two arguments whose types are integer and real. Since there is no direct coercion between mentioned types so it'll basically fail even though in reality it is possible to coerce integer into real following the route integer->rational->real.

Ex-2.83
(define (raise x)
(apply-generic 'raise x))

(define (raise-integer x)
(make-rational (contents x) 1))
(put 'raise '(integer) raise-integer)
(define (raise-rational x)
(make-complex-from-real-imag
(exact->inexact (/ (numer x) (denom x))) 0))
(put 'raise '(rational) raise-rational)

Ex-2.84-
;;we can represent the tower with a list
(define tower '(scheme-number rational complex))
;;checks if type1 is at lower level in the tower than
;;type2
;;todo: impl this
(define (before-in-tower type1 type2)
(< (listref type1 tower)))

(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 (= (length args) 2)
(let ((type1 (car type-tags))
(type2 (cadr type-tags))
(a1 (car args))
(a2 (cadr args)))
(cond
((before-in-tower type1 type2)
(apply-generic op (raise a1) a2))
((before-in-tower type2 type1)
(apply-generic op a1 (raise a2)))
(else (error "No method for these types"
(list op type-tags)))))
(error "No method for these types"
(list op type-tags)))))))

Ex-2.85- passed
Ex-2.86- passed

No comments:

Post a Comment