clara

Joel 2024-01-03T18:18:56.174789Z

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.

Joel 2024-01-03T18:28:36.393159Z

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?

2024-01-03T19:37:33.463559Z

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

2024-01-03T19:38:07.003729Z

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

2024-01-03T19:39:24.217489Z

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.

2024-01-03T19:40:07.544379Z

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”

2024-01-03T19:41:14.007439Z

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.

Joel 2024-01-04T00:11:56.317709Z

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.

Joel 2024-01-04T16:55:36.445569Z

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.

2024-01-04T17:04:20.813199Z

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

Joel 2024-01-04T17:04:42.101709Z

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

2024-01-04T17:06:03.344549Z

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.

2024-01-04T17:06:33.447929Z

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.

Joel 2024-01-04T17:07:18.169559Z

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.

Joel 2024-01-04T17:08:41.183309Z

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

2024-01-04T17:08:46.150959Z

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

Joel 2024-01-04T17:10:48.821729Z

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

2024-01-04T17:11:12.755169Z

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.

2024-01-04T17:12:17.070179Z

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.

2024-01-04T17:26:01.904349Z

An example of the outline of this idea is here https://gist.github.com/mrrodriguez/baaa6bf73e8a3b412970c648e208c293

Joel 2024-01-04T18:23:51.693869Z

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.

2024-01-04T18:26:17.379379Z

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

2024-01-04T18:26:56.245119Z

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

2024-01-04T18:27:53.939209Z

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