clara

apbleonard 2022-03-04T12:20:35.069839Z

Is this a valid way of looking for Foo and Bar facts that don't have the same :x field ? Is there a "better" way?

(defrule my-rule
  [Foo (= ?x (:x this))]
  [Bar (not (= ?x (:x this)))]
  =>
  (insert (->Baz)))
I find it a little hard to parse the use of (not ...) as a piece of logic together with (= ...) which is here only used for assignment to try and unify facts with the same :x .... if you see what I mean? Also interested in what happens and how it should be understood when the :x of Bar happens to be nil - which is partly what prompted this question 🙂

2022-03-05T01:37:33.229319Z

If :x is nil, then it’d just try to unify on nil.

2022-03-05T01:38:08.897029Z

In terms of how to write this rule, I don’t think I immediately see an issue with what you proposed.

2022-03-05T01:39:03.374119Z

Actually, you may want to use not=. I’m not sure unifying makes sense if you then wrap a not on it. I forget if the compiler is capable of understanding this in a meaningful way. Does it behave as you expect?

apbleonard 2022-03-15T16:23:01.176179Z

Pretty much. I think an example where the property of one fact is directly compared to the property of another without unifying would be useful. Like ...

apbleonard 2022-03-15T16:32:14.226529Z

(defrule ice-lolly
  [Drink (= ?freezing-temp freezing-temp)
  [TempReading (< temperature ?freezing-temp)]
  => (insert! (->FrozenDrink))

2022-03-15T16:35:46.595309Z

That's a common pattern. Surprised if no examples documented

apbleonard 2022-03-15T16:38:04.066289Z

Could be wrong but I had a good look in the examples too but didn't spot any.

2022-03-16T02:31:43.289339Z

Seems like it'd be a good addition then.

2022-03-16T02:32:14.790299Z

If you look through the test-rules ns in the Clara test directory you'll probably see quite a few different rule patterns that aren't in examples

2022-03-16T02:32:37.281029Z

Though some important and typical ones like the above should be documented more.

apbleonard 2022-03-10T12:12:21.127339Z

So I had never realised you could use a bound variable in ordinary LHS fact predicates before. It does say that you can in the http://www.clara-rules.org/docs/expressions/ docs page ...

apbleonard 2022-03-10T12:13:33.537239Z

... where it says "The fact type is then followed by zero or more S-expressions which can either be predicates run against a fact, or bindings, as described above." But I'm afraid I missed that.

apbleonard 2022-03-10T12:17:04.694849Z

In the same docs it also says below "If the same binding is used in multiple conditions, Clara ensures that all conditions can be satisfied with the same binding before activating the rule or query", except that it doesn't when you use it in a predicate s-expression after the fact type as described above.

apbleonard 2022-03-10T12:21:26.273649Z

There are no examples in that page of using an "earlier" (although the order doesn't matter) bound variable ?x in a predicate s-expression after the fact type such that the ?x used in there is not unified with the others. I think there perhaps should be? Been using Clara for 4 years and we've been missing out on that option for expressing rules! 🎒

apbleonard 2022-03-06T17:14:24.263189Z

Ah ok. So I guess we should be doing this. That reads better to me as I'm not left scratching my head about whether it's unifying or not 🙂

(defrule my-rule
  [Foo (= ?p (:x this))]
  [Bar (= ?q (:x this))]
  [:test (not= ?p ?q]
  =>
  (insert (->Baz)))
Also I've just now come across the destructuring part of your docs and so looks like the (:x this) parts could be cleaned up too 😊

apbleonard 2022-03-06T17:20:45.955019Z

Would have to add the "some" constraint as you said. BTW I wasn't sure what you meant by "clj function filter"? (That's what had me looking in the docs again.)

2022-03-06T17:25:32.576349Z

Your rule above looks like a contradiction.

2022-03-06T17:25:42.382269Z

That's why I was thinking you should avoid unification.

2022-03-06T17:26:01.924999Z

Unification means they are equal. Then you check them not=

2022-03-06T17:26:15.070359Z

I don't see how you can unify with constraints on not=

2022-03-06T17:26:34.055979Z

You could use negation conditions to do what you want but I'm not sure what you need from the facts that you bind

2022-03-06T17:27:55.310159Z

[Foo (= ?p (:x this))]
[:not [Bar (= ?q (:x this))]]

2022-03-06T17:28:35.689209Z

However this may be a bit different than the RHS firing pattern you wanted. This would be true for every Foo that didn't have any Bar with the same :x

2022-03-06T17:28:41.074779Z

So not quite the same I think

2022-03-06T17:29:43.052519Z

Rule condition pattern is of the form

[FactType (<constraints>)]
I was just saying that constraints are like a “filter” over the facts of FactType

2022-03-06T17:29:55.173579Z

And most things you write as constraints are regular clj functions

2022-03-06T17:30:20.144719Z

Unification is a little special

2022-03-06T17:48:33.798669Z

I believe when you have a top-level = in a constraint it is treated as a unifying bind. If you meat the = below something like not in your original rendition of this, I think the unification isn't handled specially and instead the constraint expressions are just evaluated linearly across the facts of FactType like a filter. So your original version probably did work and I misread. However I still think not= is a bit more concise and clear and you still need the some? check for your nil handling.

apbleonard 2022-03-05T21:03:11.777709Z

Well the rule was meant to fire to show a problem when the user had supplied an (Foo) :x which was different to the "required" (Bar) :x , which it did - including when the supplied :x was nil. We weren't expecting that the supplied :x could ever be nil but that was our fault. But on trying to solve that bug I started squinting at this code and realising I didn't reallyknow why it was working at all. I must admit I wasn't aware of not= nor can I find docs about it? Seems in theory a tricky thing to achieve - a kind of complement to unification?

2022-03-05T21:07:35.275459Z

not= is just clj function. Not special to Clara.

2022-03-05T21:07:48.266489Z

= is a bit special since Clara uses it for unification

2022-03-05T21:08:14.854839Z

So in this case I think I'd avoid the unification and just use a “clj function filter” which not= would serve the purpose

2022-03-05T21:08:28.800199Z

If you didn't want nil. You could add a constraint for some?

2022-03-14T17:07:49.817029Z

A bit late here, but I'm not sure what scenario you're referring to @apbleonard . Do you mean something like this?

`(defrule insert-cold-temperature
  [Temperature (= ?temperature temperature) (< ?temperature 30)]
  =>
  (insert! (->Cold ?temperature))) 
`

👍 2
2022-03-14T17:08:53.272709Z

The code formatting doesn't seem to be working on my mobile unfortunately. Or did you mean something else?