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.
Related
can I use variable as a name of instance?
Example:
(make-instance [?input] (name)(age))
The name slot of an instance is predefined and stores the instance name, so when creating an instance you wouldn't specify it twice using the make-instance function. Otherwise, here's the syntax for using a variable to specify an instance name:
CLIPS (6.31 6/12/19)
CLIPS>
(defclass PERSON
(is-a USER)
(slot full-name)
(slot age))
CLIPS> (bind ?input p1)
p1
CLIPS>
(make-instance ?input of PERSON
(full-name "John Doe")
(age 23))
[p1]
CLIPS> (send [p1] print)
[p1] of PERSON
(full-name "John Doe")
(age 23)
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))
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>
I need to retrieve a slot value (passing a slot name) from an instance which may contain other instances.
Example:
(defclass MAINCONTROLLER (is-a USER)
(slot uuid
(type STRING))
(slot param
(type INSTANCE))
(multislot zones
(type INSTANCE))
(slot state
(allowed-values a b c))
(slot pump
(allowed-values on off)))
(make-instance mainController of MAINCONTROLLER
(uuid "myController123")
(param [param-mainController])
(zones [zone1] [zone2])
(state a)
(pump on))
Slot named "param" contains an instance called [param-mainController].
CLIPS documentation suggests to retrieve a slot value with a send command with put- parameter.
I tried to use a generic function to retrieve a parameter only by passing the slotname.
(defmessage-handler USER get-param (?param-name)
(printout t "Slot value: " ?self:?param-name crlf))
But executing it I get:
(send [mainController] get-param state)
[MSGPASS2] No such instance mainController in function send.
FALSE
Some questions:
1) Do I need always to define a (create-accessor read) for every slot I need to read withsend command?
2) Could you please suggest some examples with best practices to retrieve a slot value from an instance?
Thank you,
Nic
By default, get- and put- handlers are created for slots. To retrieve specific slots use (send <instance> get-<symbol>) outside of a class's message-handlers and ?self:<symbol> within. To retrieve a slot where the slot name is stored in a variable, use (send <instance> (sym-cat get- <variable>)). Using ?self:<variable> is invalid syntax for slot shorthand references.
CLIPS> (clear)
CLIPS>
(defclass MAINCONTROLLER (is-a USER)
(slot uuid
(type STRING))
(slot param
(type INSTANCE))
(multislot zones
(type INSTANCE))
(slot state
(allowed-values a b c))
(slot pump
(allowed-values on off)))
CLIPS>
(defmessage-handler MAINCONTROLLER myprint ()
(printout t ?self:state crlf))
CLIPS>
(deffunction retrieve-slot (?ins ?slot-name)
(printout t (send ?ins (sym-cat get- ?slot-name)) crlf))
CLIPS>
(make-instance mainController of MAINCONTROLLER
(uuid "myController123")
(param [param-mainController])
(zones [zone1] [zone2])
(state a)
(pump on))
[mainController]
CLIPS> (send [mainController] get-state)
a
CLIPS> (send [mainController] myprint)
a
CLIPS> (retrieve-slot [mainController] state)
a
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)))