How do I retrieve fact index in clips in a deffunction? - clips

(deffunction up ()
?fact <- u
(retract ?fact)
(assert (u green))
)
I'm trying to get something like this to work, a function to alter the states of facts, but with this it gives me an error of like ?fact is not defined. But I have done this in a defrule. Why is this not working?

Functions receive input through their parameters. Rules receive input through their patterns. If you want to pattern match, use a rule:
(defrule up
?fact <- (u)
=>
(retract ?fact)
(assert (u green)))
Alternately if you need to iterate over the existing set of facts for a deftemplate, you can use the fact set query functions (do-for-fact, do-for-all-facts, ...):
(deffunction up ()
(do-for-fact ((?fact u)) TRUE
(retract ?fact))
(assert (u green)))

Related

What's the return value of CLIPS' do-for-fact if fact has been found?

The CLIPS reference manual explains about do-for-fact:
If a fact-set satisfies
the query, the specified action is executed, and the function is immediately terminated. The
return value is the evaluation of the action. If no fact-set satisfied the query, then the return value
is the symbol FALSE.
However, I cannot find any details on what the "evaluation of the action" means in general.
Is it safe to assume that do-for-fact always returns a value not equal to FALSE if a fact has been found?
Is the following code snippet correct?
(if (not (do-for-fact ((?p1 girl boy woman man)
(?p2 girl boy woman man)
(?p3 girl boy woman man))
(and (= ?p1:age ?p2:age ?p3:age)
(neq ?p1 ?p2)
(neq ?p1 ?p3)
(neq ?p2 ?p3))
(printout t ?p1:name " " ?p2:name " " ?p3:name crlf)))
then
(printout t "Nobody found" crlf)
)
Action refers to the BNF description of the function syntax:
(do-for-fact <fact-set-template> <query> <action>*)
This action term is the same term used in the body of a deffunction:
(deffunction <name> [<comment>]
(<regular-parameter>* [<wildcard-parameter>]) <action>*)
The return value in both cases is the last action evaluated. If the last action evaluated returns the value FALSE, then the do-for-fact function will return the value FALSE just as it would if there was no fact-set that satisfied the query.
In your example, the printout function has no return value which is treated as a non-FALSE value by the not function, so it will work as you expect
CLIPS> (printout t)
CLIPS> (not (printout t))
FALSE
CLIPS>
If you had included the symbol FALSE after the printout call, then the return value of the do-for-fact call would always be FALSE regardless of whether any fact-set satisfied the query.
(printout t ?p1:name " " ?p2:name " " ?p3:name crlf)
FALSE))

Testing for presence in a multifield - CLIPS

I want to add a condition to the LHS of a rule which tests if a certain symbol appears somewhere in the multislot of a template.
For example, in the code below I would like to substitute the comment with whatever expression makes this work.
(deftemplate foo
(slot field
(type STRING)
)
(multislot multifield
(type INTEGER)
)
)
(deftemplate bar
(slot field
(type INT)
)
)
(defrule rule
(foo (field ?f1) (multifield $?mf1))
(bar (field ?f2))
; IF f2 IS AN ELEMENT OF mf1
=>
(assert (relation f1 f2))
)
What is the syntax here?
I needed to use the member$ function!
(test (member$ ?f2 ?mf1))

CLIPS: One-time pattern matching a value of a multislot

I read in this SO answer that
When an instance is created or deleted, all patterns applicable to
that object are updated. However, when a slot is changed, only those
patterns that explicitly match on that slot are affected.
Now I have the following problem:
I have a multislot that receives more and more items over time.
I have a rule R1 that fires if "some_value" is contained in the multislot. When I add "some_value" to the multislot everything works as expected. However, if I add another item, say "another_value" to the multislot, R1 fires again. This is consistent to what I cited above, but it is not what I want. I want R1 to fire only once if "some_value" is contained in the multislot, and I don't want R1 to fire again if another value is added to the multislot.
How can I do that?
I could use many slots instead of a multislot, but this would not work in case I don't know the number of possible values.
If you can't assign the values to different slots--which is how you'd normally handle firing rules on selected changes--then you need to track which changes have been processed. Tracking either the rules or values that have been processed would be the most straightforward way to do this. If each rule processes just one value, then tracking the rules would be better so that you could have multiple rules triggered for the same value change. Here's an example where rules R1 and R2 are restricted to a single change and rule R3 exhibits the behavior you're currently experiencing:
CLIPS> (clear)
CLIPS>
(defclass XAMPL
(is-a USER)
(multislot properties)
(multislot processed))
CLIPS>
(definstances initial
([x1] of XAMPL))
CLIPS>
(defrule add_some_value
(declare (salience -1))
?o <- (object (name [x1])
(properties $?p&:(not (member$ some_value ?p))))
=>
(modify-instance ?o (properties some_value ?p)))
CLIPS>
(defrule add_another_value
(declare (salience -2))
?o <- (object (name [x1])
(properties $?p&:(not (member$ another_value ?p))))
=>
(modify-instance ?o (properties another_value ?p)))
CLIPS>
(defrule R1
?o <- (object (name [x1])
(properties $?properties&:(member$ some_value ?properties))
(processed $?processed&:(not (member$ R1 ?processed))))
=>
(modify-instance ?o (processed ?processed R1))
(printout t "Rule R1 fires" crlf))
CLIPS>
(defrule R2
?o <- (object (name [x1])
(properties $?properties&:(member$ some_value ?properties))
(processed $?processed&:(not (member$ some_value ?processed))))
=>
(modify-instance ?o (processed ?processed some_value))
(printout t "Rule R2 fires" crlf))
CLIPS>
(defrule R3
(object (name [x1])
(properties $?properties&:(member$ some_value ?properties)))
=>
(printout t "Rule R3 fires" crlf))
CLIPS> (reset)
CLIPS> (run)
Rule R2 fires
Rule R1 fires
Rule R3 fires
Rule R3 fires
CLIPS>

CLIPS finding facts not working

I have the following deftemplates in CLIPS (6.3):
(deftemplate A ( slot a ) (slot b) )
(deftemplate forSearch (slot property)(slot value))
I need to read the pair (property, value) from input, and then find the fact A whose value in the slot property is value.
If I do something like this:
(defrule r2
(forSearch (property ?c)(value ?d))
(A (?c ?d))
=>
(printout t "debug" crlf)
)
I get the following error:
[PRNTUTIL2] Syntax Error: Check appropriate syntax for deftemplate patterns.
ERROR:
(defrule MAIN::r2
(forSearch (property ?c) (value ?d))
(A (?c
What should I do now?
You have to write to slot name in the pattern matching part of the rule.
The correct sintax is:
(defrule r2
(forSearch (property ?c)(value ?d))
(A (a ?c) (b ?d))
=>
(printout t "debug" crlf)
)
I don't understand what you want to accomplish, and I know it's late, but hope it helps.

how to add instances in a list?

I'm working with CLIPS and I'm getting in trouble when trying to add instances in an empty list. I'm using the insert$ function but does not seem to work properly. The concrete code is this:
(loop-for-count (?i 1 (length$ ?listaConvocatoriasAlumno))
(if (neq (nth$ ?i ?listaConvocatoriasAlumno) ?convocatoria)
then
(if (eq (str-compare (send (instance-address * (nth$ ?i ?listaConvocatoriasAlumno)) get-cuadrimestre) ?cuadrimestre) 0)
then
(insert$ ?listaConvocatoriasMismoCuadrimestre (+ (length$ ?listaConvocatoriasMismoCuadrimestre) 1) (nth$ ?i ?listaConvocatoriasAlumno))
)
)
)
?listaConvocatoriasAlumno contains multiples instances of a certain class and I would like to add some of these into another list (?listaConvocatoriasMismoCuadrimestre in this case) which at the beginning of the loop is empty.
Any idea?
Thank you very much in advance!
Just forgot to store the insert return value into the list variable... I'm getting old

Resources