I want to match a complex pattern with clips: It involves the detection of simple facts and, in a second step, the detection of more complex instances whose creation requires processing the simple facts. Currently, I approach this with three rules:
Rule1
checks for a large number of simple facts and, if present, creates a complex class instance i_complex
based on the matched simple facts.Rule2
also looks for the simple facts and i_complex
and, if present, uses them to create an even more complex instance i_really_complex
.Rule3
also looks for the simple facts, i_complex
, and i_really_complex
and, if all present, prints something to the screen.My current approach is to copy paste the large number of simple facts from the LHS of Rule1
to the LHS of Rule2
and Rule3
. This is obviously not perfect.
I have considered the following alternative:
Putting everything in one rule. This is in fact my favored solution. The problem is that one cannot add facts/instances on the LHS of a rule. This means, for example, that I cannot check if the requirements for i_complex
are met, and if yes, create and assert it. Yet this is necessary to correctly match i_really_complex
.
I have thought of a self-modifying rule which is called/matched twice: The first time it creates i_complex
on the RHS. The second time it can match i_complex
on the LHS and create i_really_complex
and so on.
What is the preferred approach to match a pattern like this?
All other things being equal, I'd suggest choosing the approach which is most maintainable. So a few simpler rules would be better than one large unwieldy and/or self modifying complicated rule.
Patterns will be shared for rules using the same set of initial patterns, so there's not a large computational burden for duplicating the patterns for multiple rules, but it does make the rules more difficult to maintain since changes to those common patterns will need to be made across multiple rules.
In your case if i_complex is only generated as a result of the detection of the simple facts, the existence of i_complex indicates that those facts are present and thus the conditions for those simple facts do not need to be included in other rules that match on i_complex. Similarly the existence of i_really_complex would indicate that the simple facts and i_complex exist.
In the case that i_complex or i_really_complex do not contain all of the variable values from the simple facts matched, you could include these as part of the instances or create facts to represent these values.
For example, these rules:
(defrule rule1
(a ?x)
=>
(assert (conclusion 1 ?x)))
(defrule rule2
(a ?x)
(conclusion 1 ?x)
(b ?x)
=>
(assert (conclusion 2 ?x)))
(defrule rule3
(a ?x)
(conclusion 1 ?x)
(b ?x)
(conclusion 2 ?x)
(c ?x)
=>
(assert (conclusion 3 ?x)))
Could be rewritten as:
(defrule rule1
(a ?x)
=>
(assert (conclusion 1 ?x)))
(defrule rule2
(conclusion 1 ?x)
(b ?x)
=>
(assert (conclusion 2 ?x)))
(defrule rule3
(conclusion 2 ?x)
(c ?x)
=>
(assert (conclusion 3 ?x)))
If you need to verify in subsequent rules that preconditions remain true, you can use the logical conditional element:
(defrule rule1
(logical (a ?x))
=>
(assert (conclusion 1 ?x)))
(defrule rule2
(logical (conclusion 1 ?x)
(b ?x))
=>
(assert (conclusion 2 ?x)))
(defrule rule3
(logical (conclusion 2 ?x)
(c ?x))
=>
(assert (conclusion 3 ?x)))