Hi all, (in the google-group the title is Infinite Loop when using :not-guard in a rule) I tried to do something that is really easy to do in e.g. Datalog, like having given a node->parent relationship, I try to get hold of all the parents that are around (no duplicates). This snippet show the data-model with the rule:
(defrecord Node2Parent [node parent])
(defrecord Node [node])
(r/defrule insert-all-parents
[Node2Parent (= ?parent parent)]
[:not [Node (= node ?parent)]]
=>
(r/insert! (->Node ?parent))
)
The way I read this is that we add a new Node
-fact for each occurring parent, that has not been added already.
And here's how I call it:
(defn s [] (-> (r/mk-session 'engine.core) (r/insert (->Node2Parent :inner1 :root)
(->Node2Parent :leaf1 :root)
(->Node2Parent :leaf2 :inner1)
(->Node2Parent :leaf3 :inner1))
(r/fire-rules)))
(r/defquery all-nodes "all nodes"
[]
[Node (= ?node node)])
(r/query (s) all-nodes)
It goes into a infinite loop and never comes back. Adding a print-statement to the rule tell you that it keeps adding :root nodes to the fact-base.
I guess that I miss something the way the unification in the LHS-conditions play out.
thanks and regards
markus@markus.frick the issue here is that Clara performs "truth maintenance". The better way to interpret the Node2Parent rule is, "Every Node which does not have a parent, should have a parent."
In this case, it confuses Clara. Clara sees a node with no parent and decides it should have one. Then it sees that the node has a parent, and therefore shouldn't have one, and therefore retracts it.
If there's no other way for Node to be created, just remove the :not. If there is, you'll likely have to restructure it.
You could also use an unconditional insert, as this would remove the fact from truth maintenance.
oh thanks a lot; I totally missed the "truth maintenance" aspect (coming from a Datalog world where rule-evaluation is monotonous). I guess it's just easier to understand and implement, if I add the Node
-facts by hand and add them to the session before I execute the rules. More so, since I won't get rid of the duplicate facts anyway.
With unconditional inserts I get
({:?node :root} {:?node :inner1} {:?node :inner1} {:?node :root})
I guess set semantics are just really difficult to have in a world where you just see the fixed number of facts from the LHS.
thanks, markus