(ns e2-77-to-80
  (:use clojure.test))

(put 'real-part '(complex) real-part) (put 'imag-part '(complex) imag-part) (put 'magnitude '(complex) magnitude) (put 'angle '(complex) angle)

Well, let's remember the structure of the number which works with our enhanced datatype-dispatch mechanism.

-> [|] -> [|] -> [|] | | | | [complex] [rectangular] [3] [4]

The first row of the above represents the structure of the cons cells, while the third represents the contents of those cells. In other words, a complex number with a rectangular representation is represented by a

(list 'complex 'rectangular x y)

Now, what's going to happen when we call magnitude on a record having the above structure?

1) magnitude calls apply-generic 'magnitude 2) apply-generic gets the procedure registered with put (which is magnitude) 3) magnitude is called one more time with arguments stripped from the 'complex tag (so that only the 'rectangular tag remains) 4) apply-generic gets called with 'rectangular arguments which we already know how to process

(defn attach-tag [type-tag contents]
  (cond (or (symbol? contents) (number? contents)) contents
        :else (cons type-tag contents)))
(defn type-tag [datum]
  (cond (symbol? datum) 'scheme-symbol
        (number? datum) 'scheme-number
        (seq datum) (first datum)
        :else (throw (IllegalArgumentException. (format "Datum %s doesn't contain any type tags" datum)))))
(defn contents [datum]
  (cond (or (symbol? datum) (number? datum)) datum
        :else (second datum)))
(deftest test-278
  (is (= (attach-tag nil 1) 1))
  (is (= (attach-tag 'any 'a) 'a))
  (is (= (attach-tag 'any ['a]) (cons 'any ['a])))
  (is (= (type-tag 1) 'scheme-number))
  (is (= (type-tag 'a) 'scheme-symbol))
  (is (= (type-tag ['lol 1]) 'lol))
  (is (= (contents 1) 1))
  (is (= (contents 'a) 'a))
  (is (= (contents ['lol 1]) 1)))
(defn apply-generic [op & args] nil)
(defn real-part [x] nil)
(defn imag-part [x] nil)
(defn put [op tag proc])
(defn eq-contents [a b]
  (= (contents a) (contents b)))
(defn eq-rect-polar [a b]
  (and (= (real-part a) (real-part b))
       (= (imag-part a) (imag-part b))))
(put 'equ? '(rational rational) eq-contents)
(put 'equ? '(rectangular rectangular) eq-contents)
(put 'equ? '(polar polar) eq-contents)
(put 'equ? '(rectangular polar) eq-rect-polar)
(put 'equ? '(polar rectangular) eq-rect-polar)
(put 'equ? '(complex complex)
  (fn [a b]
    (apply-generic 'equ? (contents a) (contents b))))
(put 'equ? '(scheme-symbol scheme-symbol) =)
(put 'equ? '(scheme-number scheme-number) =)
(defn numer [rat]
  (first rat))
(defn zero-number? [x] (= x 0))
(defn zero-rational? [x] (= (numer x) 0))
(defn zero-rect-polar? [x]
  (and (= (real-part x) 0) (= (imag-part x) 0)))
(put 'is-zero? 'rational zero-rational?)
(put 'is-zero? 'rectangular zero-rect-polar?)
(put 'is-zero? 'polar zero-rect-polar?)
(put 'is-zero? 'complex
  (fn [x]
    (apply-generic 'is-zero? (contents x))))
(put 'is-zero? 'scheme-symbol zero-number?)
(put 'is-zero? 'scheme-number zero-number?)