I'm guessing the second [Derived 1] is retracted after insertion, though that isn't what I want, in fact in my POC rule set I'm doing an insert-unconditional!
because the fact must survive, subsequent retraction, but I still only one exactly one instance to be inserted, i.e. one-time initialization.
@dave.tenny you know you’re inserting a vector there right?
Just noticed that this seems odd (insert! [Derived ?x])
Lol, I looked at it thinking "something isn't right here" too
Just too Friday-minded to see it, thanks for looking
however, with insert!
I think you may get in an infinite loop
because your rule becomes a logical contradiction
So I think there are just several different topics with this example, 😛
yes indeed, infinite loop
you can do an insert-unconditional!
of course
Amending the snippet
I’m not a huge fan of those, because they cause rules to become more order dependent’
However, there are times where they are difficult to avoid I know
In my case, I need to add a fact to the system, once to "initialize" the absense of a missing fact. The fact needs to survive truth maintenace because I am going to retract the basis for creating it, but not the need for using it later on
Your snippet now has no code, only output
yeah, once sec, reposting the snippet, there was no "edit"
I deleted the first snippet, it shouldn't exist at all in slack, actually.
Anyway, I'm clearly not yet in the mindset of thinking the way clara wants me to think. I'd expect a rule like [:not [Foo]] => (insert-unconditional! (->Foo))
to fire exactly once, but clearly my assumptions are wrong.
Wouldn’t call that a bad assumption but that rule effectively means when not foo foo and when foo not foo
if you use insert!
the behavior is a contradiction, with insert-unconditional!
it is different
There is also a property you can add to rules, I don’t typically like to add it though, but it is :no-loop
Oops. with unconditional it should operate as you stated I think
it may be able to stop a logical loop from a contradicting rule like you have here with insert!
, but I’d have to mess with that again
Oops, yes, my code snippet iwth the infinite loop isn't interesting. When I use insert-unconditional
it's still firing more than once
@alex-dixon I haven’t seen an insert-unconditional!
example yet 😛
Doing the code snippet and output again, apologies
insert-unconditional!
will result in a firing for each of your Fact
objects, so 3 is rigth
@dave.tenny uploaded a file: https://clojurians.slack.com/files/U7SGKB4LF/FAW88NZQU/why_are_multiple_derived_1_values_inserted__how_can_i_prevent_it_.clj
What about not exists?
I thought [:not [Foo]]
was a not-exist check?
The rules do not treat the working memory as something like a set. It allows “duplicates”. There are useful cases for that - scratch this
oh, I see what you mean
@dave.tenny you’re correct in what :not
is
I think it may be an “edge case” on insert-unconditional!
behavior in the engine. I’d probably call it incorrect how the engine is behaving
I'm confused because on the one hand, the RHS of one rule can impact the firing of another rule. But in this case it's like both checks for a [Derived 1] correpesponding to a [Fact 1] took place at the same time, neither aware of the others effect, and unsure how to bridge that.
Like I said, I’m not a fan of insert-unconditional!
and try to not use it much because I think it makes things have order dependence and always trickier to reason about as far as “global logical consistency” across the rules
(reminds me of MVCC transactions, which can be a good thing ... in a database 😉 )
However, in this case, I think it is behaving poorly with batched inserts
I think all 3 matches are staged independent of one another and all perform insert-unconditional!
at the “same time”
since they are unconditional, the truth maintenance isn’t used to remove the logical inconsistencies
this is a tougher case to me conceptually to think about
as far as a “fix” would go
Okay, well, I'll remedy my immediate problem by doing what is fundamentally an initialization step outside of the rule firing and add my initialization outside of the firings (i.e. not in an RHS via insert!
, but via insert
externally.
Wondering if behavior is different if derived is inserted without ?x...maybe y instead
I'm definitely still struggling with these little things, though logic principles of [not x] => [x]
is a good way ot look at it in my thinking for the future.
@dave.tenny oftentimes, and I’ve said this quite a bit here before, I try to separate the desire of “cardinality” into a different rule from the rule that has the logic to derive the fact in question
This particular one is very unfortunate though, if it worked it was much nicer and more foolproof when done via a rule firing.
So instead of worrying about a rule producing too many of something, I let it produce them, and reconcile them with a separate rule and an accumulator
@mikerod what’s the upside to the batched unconditional insertions implementation? Is it possible to still attain those benefits without eliciting behavior like this?
this case is a bit different in a way, but if your real concern is only that you don’t want 2 Derived :y 1
facts, it applies
@alex-dixon batched <anything> upside is basically always performance
and the performance can be really significant
However, in the unconditional case, it now concerns me a bit since the truth maintenance won’t “fix it” when different unconditional inserts cause the other to become untrue
however, that is a really gray area to me. if it did behave right, how would it choose which unconditional insert wins, when they contradict each other? In the general case.
I guess it would just have to be order-dependent
On an unrelated topic, can you recommend tools for pretty-printing/organizing inspect
and get-trace
output to assist with reading it? I made my first attempt at decoding that stuff to debug, but as a raw clojure nested structure it's rough going for a first try.
@dave.tenny @alex-dixon is going to release a tool to show tracing stuff nicer 😛
Joking.. but he has said he had a better visualization thing. The trace results will be pretty verbose and clj data structures. Inspect was supposed to have a few friendlier printers I think. I haven’t used inspect much.
Of course what I really want is a simple movie-mode rule tracing with verbose-mode description of clause evaluation impact on rule consideration/rejection. Heh, or is that [:test (do (prn "here I am") true)]
in the LHS?
@dave.tenny yeah, you can print stuff. I think the tracing output can be used alright, but it’s mostly just composing functions on it to show it however is useful.
I don’t have any great pointers there still beyond that
Haven't seen any "tips and tricks" documentation for the sorts of things a newbie could use for debugging
if it's out there
Yeah, I think this may be something that is lacking (and would be really nice to have).
The most docs I see are just from http://www.clara-rules.org/docs/inspection/
@mikerod It’s not better according to me. And yeah…I’m working on it again this weekend 🙂
Might open an issue in Clara about adding Datalog syntax as a separate clara library. For something like the precept devtools concept I’m not sure how that would work….would need to think about it or have some direction from others. A lot of the way I thought about it was Precept-specific. I think the main difference is that there’s framework to manage session transitions, so there’s code that’s aware of when rules are firing and when they’re done firing that allows them to be identified and numbered
Sorry if that’s incoherent
@alex-dixon Yeah, I’d have to think about that more too. I get what you are saying though I think.