Fork me on GitHub
#clara
<
2017-06-30
>
flipmokid10:06:29

Hopefully a quick one, I'm using clara with :fact-type-fn (fn [[e a _]] a). I'm inserting a bunch of facts e.g.

(rules/insert-all session [[1 :event/eventTypeId 1]
                                          [1 :state/timeElapsed 19]
                                          [2 :event/eventTypeId 1]
                                          [2 :state/timeElapsed 23]])
to match with an example rule of
(def football-over-20-mins-rule
  (clara-dsl/parse-rule
   [[:event/eventTypeId [[e a v]] (= 1 v) (= ?e e)]
    [:state/timeElapsed [[e a v]] (> v 20) (= ?time v) (= ?e e)]]
   (println "Event " ?e " has gone over 20 mins with " ?time)))
At some point I want to retract all facts for a given 'e', as the event might have finished and I want to keep my facts lean. What is the best way of collecting all facts for matching 'e' so that I can retract them all?

ryanbrush12:06:18

@flipmokid Your best bet is probably to write a query (via defquery) to get all facts for a given e, and then use retract to remove them. There isn't a retract-all (yet), but since it's a multi-arity function you can call it arbitrarily like (apply retract session [my-facts])

flipmokid12:06:10

Sorry, it's probably my bad understanding of rules but for my [e a v] fact type how would I get all e's out. As far as I understand the first part of a rule is the type (which is a) and so I'm not sure how I would specify how to pull all entities of a particular number. I'm currently inserting a fact [e :event/retract true] and then trying to find these [:event/retract [[e a v]] (= v true) (= ?e e)] but not sure how to get all matching facts that have the same e

flipmokid12:06:59

I guess I just need someone to help me understand how to write a rule/query that can pull the e's (it's having to write the type at the start that is throwing me). I'm not sure if I can check for the :event/retract fact and then have an accumulator to get all e's for it

ryanbrush13:06:22

I think I see the sticking point here. You'll probably want to match a query on a special "parent" type of all (you can use clojure.core/derive to declare a parent type, which Clara will honor if it's done before the session is created.) Then the query can have a predicate to match on whatever subset you want.

ryanbrush13:06:29

...or I suppose you could just have your fact match on java.lang.Object (assuming your running the Clojure rather than the ClojureScript version) and have your predicate check that.

flipmokid13:06:56

I'm not sure derive will be of much help. For a fact [e a v] e will always be a number (the id of the sporting event) which is not known in advance, a will be the attribute and v can be anything e.g. [1 :state/timeElapsed 19] So do you think if I wanted to stick with my tuple-shaped facts it would be difficult to extract all es of the same value if my fact-type-fn is (fn [[e a v]] a)? Out of interest do you know how Precept handles retractions of its tupled shaped facts?

ryanbrush13:06:31

If you know the values of a ahead of time then it derive could work, but might be painful to derive all of that. But a defquery approach might work like:

ryanbrush13:06:38

`(defquery [:e-to-remove] [Object [my-tuple] (= ?e-to-remove (first my-tuple))])

ryanbrush13:06:59

Haven't actually tried that, but it's an idea to try with. I'm not familiar with how Precept handles this sort of thing.

flipmokid13:06:55

That looks interesting, let me give it a go

ryanbrush13:06:43

Sounds good. There are some steps I left out...you'll want to return the full tuples from the query, for instance, so they can be retracted.

flipmokid13:06:36

Actually, I'm not sure the Object part will match as I'm not using the type function (please let me know if I'm being stupid though, I often am!) (defquery [:e-to-remove] [Object [my-tuple] (= ?e-to-remove (first my-tuple))])

ryanbrush14:06:02

Ah, of course. You'll need a custom ancestors function to complement the custom type function. There is an example here: http://www.clara-rules.org/docs/fact_type_customization/

ryanbrush14:06:38

So your custom ancestor could just return :all-facts if you wanted to match everything. 😉

ryanbrush14:06:12

(:all-facts is just an arbitrary keyword here that could be returned by the ancestors function.)

flipmokid14:06:15

Ah okay. I'll try that. Thanks for your help so far, I really appreciate it

flipmokid15:06:18

Brilliant that worked!

(def retractions-rule
  (clara-dsl/parse-rule
   [[:event/retract [[e a v]] (= v true) (= e ?e)]
    [?elems <- (acc/all) :from [::all [[e _ _]] (= e ?e)]]]
   (println "RETRACTION MATCHED " ?elems)))
Many thanks for your help