 (ns chapter3.leibniz
   (:refer chapter3.match :only [match match-state atom?])
   (:refer clojure.test :only [with-test is run-tests]))
+
+(defrecord rule [pattern action name])
 (defn nested-diff-sum? [d v]
   (and (not (atom? v)) 
        (when-let [d2 (match-state '(+ (? e1) (? e2)) v)]
          (merge d d2))))
 (def diff-sum-rule
-  ['(d (nested-diff-sum? e3) (? v1))
+  (->rule '(d (nested-diff-sum? e3) (? v1))
    #(list '+ (list 'd (% 'e1) (% 'v1)) (list 'd (% 'e2) (% 'v1)))
-   "diff-sum-rule"])
+   "diff-sum-rule"))
 (defn nested-diff-x1? [d v] d)
 (defn nested-diff-x2? [d v] (and (= v (d 'e1)) d))
 (def diff-x-rule
-  ['(d (nested-diff-x1? e1) (nested-diff-x2? e2))
+  (->rule '(d (nested-diff-x1? e1) (nested-diff-x2? e2))
    (fn [d] 1)
-   "diff-x-rule"])
+   "diff-x-rule"))
 (with-test
   (defn exists-tree? [f v1]
     (if (atom? f)

  (is (exists-tree? '((2 3) (4 (5) 3) 2 1) 1)))
(defn diff-const-e2-rule [d x] (and (not (exists-tree? (d 'e1) x)) d))
(def diff-const-rule
  ['(d (? e1) (diff-const-e2-rule e2))
   (fn [d] 0)
   "diff-const-rule"])
(defn diff-product-e3-rule [d x]
  (and (not (atom? x))
       (when-let [d2 (match-state '(* (? e1) (? e2)) x)]
         (merge d d2))))
(def diff-product-rule
  ['(d (diff-product-e3-rule e3) (? v1))
   (fn [d] (list '+
                 (list '* (d 'e2) (list 'd (d 'e1) (d 'v1)))
                 (list '* (d 'e1) (list 'd (d 'e2) (d 'v1)))))
   "diff-product-rule"])
(defn number-state? [d x]
  (when (number? x) d))
(defn diff-power-e3-rule [d x]

      (when-let [temp (try-rule-on-list rule (rest expressions))]
        (cons (first expressions) temp)))))
(defn fire [rule d]
  ;(println (:name rule) "fires.")
  ((:action rule) d))
(defn try-rule [rule expression]
  (if (atom? expression)
    nil
    (if-let [d (match-state (:pattern rule) expression)]
      (fire rule d)
      (try-rule-on-list rule expression))))
(with-test
