oracle-samples/clara-rules

Rule with just [:not A] => (insert A) seems broken

Closed this issue · 2 comments

I have this code:

(defrecord Dice [dice])

(cr/defrule dice
  [:not [Dice]]
  =>
  (cr/insert! (->Dice 1))
  (println "inserted dice")
  (Thread/sleep 100))

(defn test-clara []
  (-> (cr/mk-session)
    cr/fire-rules))

I expect this to fire the dice rule once and nothing else. But it just keeps firing it. This is my output:

game.server.core> (test-clara)
inserted dice
inserted dice
inserted dice
inserted dice
inserted dice
inserted dice
inserted dice
inserted dice

If I interrupt that and check the rule it's:

game.server.core> dice
{:ns-name game.server.core,
 :lhs [[:not {:type game.server.core.Dice, :constraints []}]],
 :rhs
 (do (cr/insert! (->Dice 1)) (println "inserted dice") (Thread/sleep 100)),
 :name "game.server.core/dice"}

I'm having (Thread/sleep 100) in there because otherwise the REPL becomes unresponsive when it is stuck in a loop.

Even weirder is that I had some problems with old rules still being defined (because of defrule) so I restarted Clojure, multiple times. And sometimes the rule does work ("inserted dice" printed only once) and sometimes it doesn't. I felt like I was going mad.

Also, I tried with

(cr/defrule dice
  [:not [Dice]]
  [?dice <- (acc/count) :from [Dice]]
  =>
  (cr/insert! (->Dice 1))
  (println "inserted dice")
  (println "number of dice:" ?dice)
  (Thread/sleep 100))

And it prints:

inserted dice
number of dice: 0
inserted dice
number of dice: 0
inserted dice
number of dice: 0

forever.

Zylox commented

This is called truth maintenance. http://www.clara-rules.org/docs/truthmaint/

Your rule inserts a Dice fact, which causes ':not Dice' to no longer be true, so it retracts Dice, which causes ':not Dice' to be true, which inserts a Dice, and so on and so forth.

Oh, of course. Thanks @Zylox