Fork me on GitHub

I have it working with a callback and unconditional insert. I don't think there's a way to do a logical insert in the context of the callback. The session has already moved forward, could have been modified further by the time the callback is called, etc.


I haven’t played around with it much. Typically I do the same as you I think….wait to handle it on the next fire-rules iteration, but that can be problematic in certain cases. So I’m kind of curious about being able to park/block within the RHS but I haven’t thought about it much. It might be convenient for Javascript but in a parallel or multiple thread environment…I dunno. I forget the case I ran into where I really did want to stop the world / rule activations until I could get a result, but I feel like that’s more an error in my thinking than a feature I need to figure out how to support. Don’t know though


Part of what I was finding was that beyond the simple request/response case there was a proliferation of auxiliary fact types to deal with requests from the UI. For example, if the user toggled the "Favorite" button on an article, I would insert a FavoritedArticle fact, which in turn triggered Request to be inserted, along with a rule to handle the response to that Request. I also had to add clean up rules to get rid of these FavoritedArticle facts when the page changed, as well as properly manage upsertion vs. insertion, etc. It was all starting to feel a bit fiddly. But I think you could actually do this with the same Request/`Response` pattern, just replacing making an HTTP request with rendering the UI which will generate the Response.


So for precept I implemented something like the following. Below is somewhat similar to Redux in Javascript which also reifies this and request/response/fail for api calls for front-end state management.

(defrecord Action [type payload])

(defrule actions-only-survive-one-call-to-fire-rules
{:salience -100}
 [?fact <- Action]
(retract! Action)

(defrule on-article-favorited
{:salience 100}
[Action (= ?type :article-favorited) (= ?payload payload)]
;; Still have the async dance but Action facts are automatically cleaned up at the end


Right. I'm trying to do this without salience, just to see where it takes me in terms of design, possible changes to clara, etc. One thing that has fallen out is that I think the fact-based immutable history approach of precept is probably the way to go, as opposed to using whole entities as facts and trying to update "in place".


Would you consider agenda groups? I’ve very little experience with systems that use them but we try to simulate them partially in precept by using Clara’s :activation-groups and :activation-group-sort-fn


So we have :group :cleanup I think, which is given least precedence in the sort fn


I still run into wanting update in place but I’m on the fence about it because immutability is easier for me to understand. Case that comes up a lot is a default value:

(rule when-no-user-selected-article
 [:not SelectedArticleId]
  [?most-recent <- (acc/min :time :returns-fact true) :from [Article]]
(insert! (->SelectedArticleId (:id ?most-recent)))


So that loops


There’s a :no-loop prop that’s relatively undocumented. Haven’t played with it but seems like it would solve this case. A (modify!) wouldn’t I guess because the SelectedArticleId doesn’t exist. If it did as something like (SelectedArticleId :unset) then you could match on (= id :unset) and (modify! ?selected-article :id (:id ?most-recent))


I need to think about it. But I really am trying, as an exercise, to see what happens if you constrain yourself solely to the logical consistency implied by clara. I think I'm converging on something, but I've thought that before only to trip over an ugly fact that ruined my beautiful theory.


BTW, the "real world" example app (conduit) is proving to be a great way to exercise this stuff. You might find it useful for precept development.


Yeah was thinking same! Would be nice to see it and Clara on their official list as well