exercise-2.81-identical-coercion.rkt 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. ;; "Coercion" is the process of viewing data of a specific type as data of another type and acting accordingly.
  2. ;; For example an integer number might be viewed as a rational number and added to another rational number, by a procedure, which only can work with rational numbers.
  3. (define (apply-generic operation . args)
  4. ;; getting all type tags
  5. (let ((type-tags (map type-tag args)))
  6. ;; getting the specific operation from the table of operations
  7. ;; for the type tags we got
  8. (let ((procedure (get operation type-tags)))
  9. (if
  10. ;; if there is such a procedure
  11. procedure
  12. ;; we simply apply it to the contents of all arguments (which are data of some types) :)
  13. (apply procedure (map contents args))
  14. (if
  15. ;; otherwise, we check if we have 2 arguments
  16. (= (length args) 2)
  17. ;; if we have 2 arguments, we get the types into the constants type1 and type2
  18. ;; and get the arguments separated in a1 and a2
  19. (let ((type1 (car type-tags))
  20. (type2 (cadr type-tags))
  21. (a1 (car args))
  22. (a2 (cadr args)))
  23. ;; with these constants
  24. ;; we find the coercion procedures for the types
  25. (let ((t1->t2 (get-coercion type1 type2))
  26. (t2->t1 (get-coercion type2 type1)))
  27. (cond
  28. ;; if there is a coercion procedure for coercion from type1 to type2
  29. (t1->t2
  30. ;; we apply the operation to the coerced a1 and not coerced a2
  31. (apply-generic operation (t1->t2 a1) a2))
  32. ;; if there is a coercion procedure for coercion from type2 to type1
  33. (t2->t1
  34. ;; we apply the operation to the not coerced a1 and coerced a2
  35. (apply-generic operation a1 (t2->t1 a2)))
  36. ;; otherwise
  37. (else
  38. ;; we print an error
  39. (error "No method for these types"
  40. (list operation type-tags))))))
  41. ;; if the arguments are more or less than 2 arguments we throw an error
  42. (error "No method for these types"
  43. (list operation type-tags)))))))
  44. ;; Exercise 2.81
  45. ;; a. Louis Reasoner adds:
  46. (define (scheme-number->scheme-number n) n)
  47. (define (complex->complex z) z)
  48. (put-coercion
  49. 'scheme-number
  50. 'scheme-number
  51. scheme-number->scheme-number)
  52. (put-coercion 'complex 'complex complex->complex)
  53. ;; also we added
  54. ;; following added to Scheme-number package
  55. (put
  56. 'exp
  57. '(scheme-number scheme-number)
  58. (lambda (x y)
  59. (tag (expt x y))))
  60. ; using primitive expt
  61. ;; What happens if we then call the following for complex numbers?
  62. (define (exp x y) (apply-generic 'exp x y))
  63. ;; TODO
  64. ;; b. Is Louis correct that something had to be done about coercion with arguments of the same type, or does apply-generic work correctly as is?
  65. ;; c. Modify apply-generic so that it doesn’t try coercion if the two arguments have the same type.