Fork me on GitHub
#clara
<
2019-01-13
>
fricke13:01:07

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

eraserhd16:01:46

@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."

eraserhd16:01:51

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.

👍 10
👆 5
eraserhd16:01:46

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.

ethanc16:01:54

You could also use an unconditional insert, as this would remove the fact from truth maintenance.

fricke19:01:19

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