Quick little implementation of CHR in Clojure. Attempting to roughly follow CHR2 as described in Peter Van Weert's dissertation Extension and Optimising Compilation of Constraint Handling Rules
Disclaimer:
Set semantics is currently baked in. Propagation history is opt-in. No "aggregates" semantics yet. No optimizations to speak of.
Not tested. Don't build bridges that depend on this code.
(def narrowing-rules
     [(rule range-lower-bound
            [:- [:Range m1 M1]
             :- [:Range m2 M2]
             :when (number? m1)
             :when (number? m2)]
            [[:Range (max m1 m2) M1]
             [:Range (max m1 m2) M2]])
      (rule range-upper-bound
            [:- [:Range m1 M1]
             :- [:Range m2 M2]
             :when (number? M1)
             :when (number? M2)]
            [[:Range m1 (min M1 M2)]
             [:Range m2 (min M1 M2)]])
      (rule empty-range
            [:- [:Range m M]
             :when (and (number? m)
                        (number? M)
                        (< M m))]
            [[:Error (str "Empty range: [" m "," M "]")]])])
(unwrap (awake narrowing-rules [[:Range 30 90] [:Range 49 60] [:Range 'some-unground-var 59]]))
The RULE macro is just sugar; rules can be constructed directly:
(def leq-rules (fresh [x y z]
                   [{:head [[:- [:leq x x]]]}
                    {:head [[:- [:leq x y]]
                            [:- [:leq y x]]]
                     :body [[:equals x y]]}
                    {:head [[:+ [:leq x y]]
                            [:+ [:leq y z]]]
                     :body [[:leq x z]]}]))
(defn generate-leq-facts
  [pairs-o-symbols]
  (unwrap (awake leq-rules (map (fn [[l u]] [:leq l u]) pairs-o-symbols))))`
(def gcd-rules (fresh [n m]
                   [{:head [[:- [:gcd 0]]]}
                    {:head [[:+ [:gcd n]]
                            [:- [:gcd m]]]
                     :guards [(chrfn [m n] (>= m n))]
                     :bodyfn (chrfn [m n] [[:gcd (- m n)]])}]))
(defn find-gcd [n1 n2]
  (unwrap (awake gcd-rules [[:gcd n1] [:gcd n2]])))