Skip to content

Instantly share code, notes, and snippets.

@taylorSando
Created June 5, 2014 01:15
Show Gist options
  • Save taylorSando/36e7f6593e503a38bb10 to your computer and use it in GitHub Desktop.
Save taylorSando/36e7f6593e503a38bb10 to your computer and use it in GitHub Desktop.
Datomic recursion using rules
(defn recursive-rule
"A recursive rule for establishing prototype inheritance/isa relationship.
Can specify a maximum depth to travel, or none if there are no restrictinos.
rule The name of the rule
e The entity
a The attribute
v The value
Should be creating the rule like: (recursive-rule 'isa '?e '?a '?v)
Then within a query, can refer to it like this:
(isa ?e :thing/isa ?v) "
([rule e a v]
(let [p '?p]
[[(list rule e a v)
[e a v]]
[(list rule e a v)
[e a p]
(list rule e a p)]]))
([rule e a v depth]
(let [r [[(list rule e a v ) [e a v]]]
get-sym (fn [i] (symbol (str (name e) i)))]
;; When there is only a depth of one
;; can simply use the starting rule
(if (= depth 1)
r
(vec (apply conj r
;; Create all the recursive rules
(for [d (range (dec depth))]
;; Create one rule
;; Make sure to turn the lists
;; into vectors
(vec (map vec (concat
;; This is the iniitial rule, e.g.
;; (rule ?e ?a ?v)
;; and is also the first condition
;; e.g. (?e ?a ?e0)
[(list rule e a v) (list e a (get-sym 0))]
;; These are the conditions in between the
;; start and ending
;; e.g. (rule ?e0 ?a ?e1)
(for [i (range 0 d)]
[(get-sym i) a (get-sym (inc i))])
;; This is the final condition for the rule
;; This is where (rule ?en ?a ?v)
;; the actual value is linked into the rule
[(list (get-sym d) a v)]))))))))))
;; Fully recursive
(d/q '[:find ?e
:in $ %
:where
; [?e]
;[(= ?e 1)]
(isa ?e :thing/isa 4)
]
[[1 :thing/isa 2]
[2 :thing/isa 3]
[3 :thing/isa 4]]
'[[[isa ?e ?a ?v]
[?e ?a ?v]]
[[isa ?e ?a ?v]
[?e ?a ?p]
(isa ?p ?a ?v)
]
]
)
;; Limit Recursive
(d/q '[:find ?e
:in $ %
:where
; [?e]
;[(= ?e 1)]
(isa ?e :thing/isa 6)
]
[[1 :thing/isa 2]
[2 :thing/isa 3]
[3 :thing/isa 4]
[4 :thing/isa 5]
[5 :thing/isa 6]]
'[[[isa ?e ?a ?v]
[?e ?a ?v]]
[[isa ?e ?a ?v]
[?e ?a ?e1]
[?e1 ?a ?v]]
[[isa ?e ?a ?v]
[?e ?a ?e1]
[?e1 ?a ?e2]
[?e2 ?a ?v]]
]
)
;; With rule-fn
(d/q '[:find ?v
:in $ %
:where
; [?e]
[(= ?e 1)]
[?v :thing/name "name"]
(isa ?e :thing/isa ?v)
]
[[1 :thing/isa 2]
[2 :thing/isa 3]
[3 :thing/name "name"]
[3 :thing/isa 4]
[4 :thing/isa 5]
[5 :thing/isa 6]]
(recursive-rule 'isa '?e '?a '?v)
)
@decoursin
Copy link

Really amazing, thank you so much, but I really think lines 15-17 should be:

      [(list rule e a v) 
       [e a p]
       (list rule p a v)]

instead of:

      [(list rule e a v) 
       [e a p]
       (list rule e a p)]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment