(ns twrule.core) ;; A is the B ;; fact: '(father a b ) (def facts #{'(father andrew bob) '(father bob charlie)}) ;; Grandfather rule: if A is the father of B, and B is the father of C then A is the Grandfather C (def rules [{:patterns ['(father ?a ?b) '(father ?b ?C)] :assertions ['(grandfather ?a ?C)]}]) (defn is-variable? [x] (= \? (first (str x)))) (defn match [p f b] (when (= (count p) (count f)) (loop [pairs (map vector p f), b b] (if (empty? pairs) b (let [[phead fhead] (first pairs)] ;(println phead fhead b) (cond (and (is-variable? phead) (contains? b phead)) (if (= fhead (get b phead)) (recur (rest pairs) b) nil) (is-variable? phead) (recur (rest pairs) (assoc b phead fhead)) :else (if (= phead fhead) (recur (rest pairs) b) nil))))))) (defn var-bindings [r facts] (defn solve [ps b] (if (empty? ps) (list b) (let [p (first ps) bs (keep #(match p % b) facts)] (mapcat #(solve (rest ps) %) bs)))) (solve (:patterns r) {})) (defn eval-pattern [p b] (for [s p] (if (is-variable? s) (get b s) s))) (defn eval-assertions [r b] (apply hash-set (map #(eval-pattern % b) (:assertions r)))) (defn instantiations [r facts] (let [bs (var-bindings r facts)] (map #(eval-assertions r %) bs))) (defn algo [f rules] (defn step [facts] (let [is (mapcat #(instantiations % facts) rules)] (if-let [i (first is)] (clojure.set/union i facts) facts))) (let [states (iterate step (apply hash-set f))] (last (take 10 states)))) (def bi {'?a 'andrew '?b 'bob '?c 'charlie}) ; (eval-pattern '(grandfather ?a ?c) bi) ;(eval-assertions (first rules) bi) ;(instantiations nil facts) ;(var-bindings (first rules) facts) (algo facts rules ) ;(match '(father ?a ?b) '(father andrew bob) {'?c 7}) ; [{'?a andrew '?b bob 'c charlie}] ;(algo facts rules)