clara

http://www.clara-rules.org/
schmee 2020-10-18T14:28:15.082Z

are rule clauses order sensitive?

schmee 2020-10-18T14:37:06.082700Z

i.e if I have

(defrule foo
  [HighCardinality (= foo ?foo)]
  [LowCardinality (= foo ?foo)]
  =>
  (insert! (->Foo ?name)))
does it matter for performance that HighCardinality is before LowCardinality?

ethanc 2020-10-18T17:41:59.087200Z

I don't believe it would impact performance. The cartesian product would be the same size I believe

1👍
schmee 2020-10-18T19:04:09.087600Z

okay, this one has me completely stumped:

(defrecord Reachable [nodeType name])
(defrecord Node [nodeType area name])

(defrule area-reachability
  [Reachable (= nodeType :area) (= name ?area)]
  [Node (= area ?area) (= nodeType ?nodeType) (= name ?name)]
  ; [:not [Reachable (= nodeType ?nodeType) (= name ?name)]]
  =>
  (insert! (->Reachable ?nodeType ?name)))

(comment
  (-> (mk-session [area-reachability])
      (insert (->Reachable :area "World"))
      (insert (->Node :room "World" "Foo"))
      fire-rules))

schmee 2020-10-18T19:04:33.088200Z

as written it finishes instantly, if you uncomment the [:not ...] it goes into an infinite loop

schmee 2020-10-18T19:11:26.088800Z

the intent is to not insert the Reachable fact if it’s already in the session

2020-10-18T19:27:32.090400Z

It’s a commmon issue @schmee and you have to rethink the LHS to be in terms of what’s true about the entire state of the system

2020-10-18T19:27:45.090900Z

So with the :not above you are expressing a logical contradiction.

schmee 2020-10-18T19:38:33.091700Z

I see, could you elaborate a bit?

schmee 2020-10-18T19:39:07.092500Z

my mental model is that since the inserted node is not of nodeType :area, it will fail to match the first clause and hence the rule as a whole will not fire

schmee 2020-10-18T19:39:17.092900Z

but that can’t be the case?

ethanc 2020-10-18T20:59:24.102Z

What Mkie is alluding to is clara's truth maintenance: http://www.clara-rules.org/docs/truthmaint/ With the not un-commented, the rule itself becomes a logical contradiction of itself. The rule will only execute and be considered true if the fact in question is not within the session. However, if the rule inserts a fact that itself asserts to be absent, then a loop would be formed. A base state would be a session without the fact in question, ergo the rule must insert the Fact. Then clara must assert that all truth has been maintained, and finds that the Fact is now present. Meaning that the Rule is no no longer true, thus a logical retraction occurs removing the Fact from the session. Then clara must asser that all truth has been maintained, again. However we are back to the base state meaning that there is no Fact within the session and the Rule is true again, thus the cycle repeats and continues forever. The wiki mentions ways to circumvent this mechanic using unconditional inserts, however these can lead to non-logical conclusions if assumptions are made.

schmee 2020-10-18T21:09:10.103100Z

thanks @ethanc, that clears things up quite a bit! I’ll take some time to ponder that and see if I can write the rule differently

schmee 2020-10-18T21:11:01.104Z

I’m coming into Clara with a Datomic mindset, which will surely trip me up a few times before I understand the “rule engine way”

sparkofreason 2020-10-18T22:33:03.106100Z

insert-uncondtional! is your friend here, if you want to have effects in the LHS of your rules. I find it easier to always use insert!, so that my rules are pure logic statements. When I want an effect, instead I insert a request fact, which is executed by some external component. That effect often invalidates the rule, thus causing the request to then be retracted by truth maintenance.

2020-10-18T22:43:16.106500Z

Yeah. I avoid unconditional in most cases.

2020-10-18T22:44:01.107900Z

You typically can phrase the problem in a way that works with TMS. Often intermediate facts and accumulators in an aggregate rule can solve common situations.