Fork me on GitHub

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
   [[: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?


@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])


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


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


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.


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


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?


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:


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


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.


That looks interesting, let me give it a go


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


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))])


Ah, of course. You'll need a custom ancestors function to complement the custom type function. There is an example here:


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


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


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


Brilliant that worked!

(def retractions-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