Fork me on GitHub
#clara
<
2024-01-03
>
Joel18:01:56

I’m wanting an accumulation, but without receiving duplicates. How can that be achieved?

(r/defrule batch
  [items? <- (acc/all) :from [Item]]
  =>
  (prn "# of items" (count ?items))
If I have items a &amp; b the first time this fire, and later I add c &amp; d, then it will on the second firing give me a, b, c, d whereas I only want c &amp; d the second time or some way to ascertain the “new items”. Looking at the https://www.metasimple.org/2017/12/23/clara-updating-facts.html I’m thinking the first approach outlined cannot work, and I’m forced to use the second approach if that even works.

Joel18:01:36

If I have a “UpdatingItem” that holds reference to the Item, it will have the same problem when attempting to capture its accumulation. If I hold some list of the “seen items” then modifying that value will also retrigger the accumulation rule, I believe in a way that will make it pointless. It seems I may be forced to use insert-unconditional! in some manner to solve this use case?

mikerod19:01:33

@UH13Y2FSA what do you mean that c & d “come later”? I think that is important to get a handle on.

mikerod19:01:07

What makes the timing of a & b differ from c & d? How are they batched and inserted in this way?

mikerod19:01:24

If you have different sources of facts, where a & b are just from a different “source” than c & d than you can reify some information onto those facts about their “source”. Then you can do eg.

(acc/all) :from [Item (= ?source-id source-id)]
which will give you accumulated “partitions” in this type of structure.

mikerod19:01:07

If this is instead insertions outside of the fire-rules loop, you could have those outside insertions have some incrementing “session ID” or something that models “different points in insertion time”

mikerod19:01:14

I think you still do intermediate facts and use a rule to explicitly match the “latest” facts either via their “source” props or their “session ID” type of props.

Joel00:01:56

What’s happening is that I’m batching a fetch of the facts for performance reasons… So that I can get the data multi-threaded. Further rules can fire that trigger another batch, but I don’t want to refetch what has already been fetched, so I effectively need to skip them.

Joel16:01:36

I did work out a mechanism sort of what you had proposed with paging, but holding the current source-id in a fact that is incremented (atom) after the current items have been processed… Subsequent Item creations use the new number.

mikerod17:01:20

Are you calling fire-rules multiple times in this flow you have?

Joel17:01:42

No, I for some reason didn’t want to go that route if I didn’t need to.

mikerod17:01:03

I’d be a bit worried about side-effects like atom updates with in a fire-rules loop. The reason is there is the truth maintenance system (TMS). It may arbitrarily fire RHS of rules and then retract them later when the LHS becomes no longer satisfied. If you perform side-effects that are not visible to the TMS, those cannot be undone. There’s a chance that what you have is still reliable. However, it is something to be leery of.

mikerod17:01:33

I’d prefer any sort of incremented mutable like this be done between successive fire-rules calls. So the TMS can operate in a “pure” env.

Joel17:01:18

I see. The problem I was running up against is that (acc/all) doesn’t get invoked when more matching facts come in. Which feels like a bug to me.

Joel17:01:41

If that had worked, then I wouldn’t have resorted to the mutation, but I’ll consider a fire-rules loop

mikerod17:01:46

It does via TMS. However, it could be something to do with your side-effects as I mentioned.

Joel17:01:48

I’ll put together a simple example of what I tried, which wasn’t mutating.

mikerod17:01:12

I’d tend to think of rules as a good way to model a tricky flow of logic. However, I’d delegate side-effects to the external caller. They can call fire-rules multiple times as some external “state” has changed.

mikerod17:01:17

So I may have a fact that represents “already fetched” facts. And use that to exclude those from any new fetch. Each fire-rules loop, I’d query out what to fetch, fetch them, and add them to an “already fetched” fact to apply to the next insert/`fire-rules` loop.

Joel18:01:51

Is using a fire-rules loop effectively any different than using insert-unconditionally? It seems like when you insert them before the fire-rules that amounts to the same thing as there is no truthiness in inserting those facts.

mikerod18:01:17

It can be similar. But you would rely on rule evaluation order with insert-unconditionally.

mikerod18:01:56

Those rules would need to go first and not interact with the TMS rules that may insert and retract multiple times seeking logical consistency.

mikerod18:01:53

So maybe not “first” but you’d need to be sure the unconditional rules aren’t meant to have any dependency on TMS managed rules.

💯 1