correlation between deffunctions and defrules CLIPS - clips

(deftemplate client
(slot idClient (type INTEGER))
(multislot nome)
(multislot birthdate)
(multislot registryCard)
(multislot endOfRegistryCard))
(deffunction reservation(?idfunc)
(build (str-cat"(defrule existsClient
(exists(client(idClient ?idfunc)))
=>
(printout t "exists" ?idfunc crlf))"
))
(run)
)
I made this deffunction and I want to see if exists the client with that idfunc that is received as parameter. what happens is that the defrule inside doesn't process this variable any thoughts how can i resolve?

I think you should set condition (assert your idfunc) and then fire the execution of your "existsClient" rule (defined as rule and not inside your function). That would be a clearer design in my opinion.

Typically you'll directly define your rules rather than using a deffunction, but here's how you can do it both ways:
CLIPS> (clear) ; Create rule and run with deffunction
CLIPS>
(deftemplate client
(slot idClient (type INTEGER))
(multislot nome)
(multislot birthdate)
(multislot registryCard)
(multislot endOfRegistryCard))
CLIPS>
(deffunction reservation (?idfunc)
(build (str-cat
"(defrule existsClient
(exists (client (idClient " ?idfunc ")))
=>
(printout t \"exists " ?idfunc "\" crlf))"))
(assert (client (idClient ?idfunc)))
(run))
CLIPS> (reservation 2)
exists 2
CLIPS> (ppdefrule existsClient)
(defrule MAIN::existsClient
(exists
(client (idClient 2)))
=>
(printout t "exists 2" crlf))
CLIPS> (clear) ; Create rule directly
CLIPS>
(deftemplate client
(slot idClient (type INTEGER))
(multislot nome)
(multislot birthdate)
(multislot registryCard)
(multislot endOfRegistryCard))
CLIPS>
(defrule existsClient
(exists (client (idClient 2)))
=>
(printout t "exists 2" crlf))
CLIPS> (ppdefrule existsClient)
(defrule MAIN::existsClient
(exists
(client (idClient 2)))
=>
(printout t "exists 2" crlf))
CLIPS> (assert (client (idClient 2)))
<Fact-1>
CLIPS> (run)
exists 2
CLIPS>

Related

How to use comparison operators on previous user input in CLIPS?

I'm a beginner to CLIPS. The goal of this program is to return the name of the company that best matches the user's demographics. I ask the user their gender and (might be storing it wrong) store it into input, ethnicity stored into input2, and age into input3. I'm running into errors when trying to do comparisons to return the company name. Eg. if input=1 (man), then compare the demographics of men in both companies and return the name of the company with more men.
(= 1 input) this line in the last rule gives me error "Function '=' expected argument #2 to be of type integer or float." which I thought I've already only allowed responses of integers. Any help would be appreciated, thank you!
(deftemplate company
(slot name)
(slot men)
(slot women)
(slot Asian)
(slot Black)
(slot Latinx)
(slot Indigenous)
(slot White)
(slot Other)
(slot <18)
(slot 18-20)
(slot 21-29)
(slot 30-39)
(slot 40+))
(deffacts demographics
(company (name Google)(men 0.669)(women 0.331)(Asian 0.428)(Black 0.088)(Latinx 0.088)(Indigenous 0.007)(White 0.445)(Other 0)(<18 0.02)(18-20 0.11)(21-29 0.59)(30-39 0.19)(40+ 0.07))
(company (name Apple)(men 0.652)(women 0.348)(Asian 0.279)(Black 0.094)(Latinx 0.148)(Indigenous 0.007)(White 0.438)(Other 0.032)(<18 0.01)(18-20 0.1)(21-29 0.57)(30-39 0.22)(40+ 0.06)))
(defrule begin => (assert (phase select-gender)))
(defrule menu (phase select-gender) =>
(printout t "Do you identify as a (1) man or (2) woman?: ") (assert (userinput (read))))
(defrule selection-okay
?phase <- (phase select-gender)
?input <- (userinput ?select&1|2)
=>
(retract ?phase)
(assert (selection ?select))
(assert (phase select-ethnicity)))
(defrule selection-nokay
?phase <- (phase select-gender)
?input <- (userinput ?select&~1&~2)
=>
(retract ?phase)
(assert (phase select-gender))
(printout t ?select " is not a valid response. Please enter 1 or 2."crlf))
(defrule menu2 (phase select-ethnicity) =>
(printout t "Do you identify as (1)Asian, (2)Black, (3)Latinx, (4)Indigenous, (5)White, or (6)Other?: ") (assert (userinput2 (read))))
(defrule selection-okay2
?phase <- (phase select-ethnicity)
?input2 <- (userinput2 ?select&1|2|3|4|5|6)
=>
(retract ?phase)
(assert (selection ?select))
(assert (phase select-age)))
(defrule selection-nokay2
?phase <- (phase select-ethnicity)
?input2 <- (userinput2 ?select&~1&~2&~3&~4&~5&~6)
=>
(retract ?phase)
(assert (phase select-ethnicity))
(printout t ?select " is not a valid response. Please enter 1 through 6."crlf))
(defrule menu3 (phase select-age) =>
(printout t "You are age: (1)<18, (2)18-20, (3)20-30, (4)30-40, (5)40+?: ") (assert (userinput3 (read))))
(defrule selection-okay3
?phase <- (phase select-age)
?input3 <- (userinput3 ?select&1|2|3|4|5)
=>
(retract ?phase)
(assert (selection ?select))
(assert (phase company-gender-men)))
(defrule selection-nokay3
?phase <- (phase select-age)
?input3 <- (userinput3 ?select&~1&~2&~3&~4&~5)
=>
(retract ?phase)
(assert (phase select-age))
(printout t ?select " is not a valid response. Please enter 1 through 5."crlf))
(defrule get-company-by-gender-men
?phase <- (company-gender-men)
(= 1 input)
(> (fact-slot-value 1 men) (fact-slot-value 2 men))
=>
(retract ?phase)
(printout t (fact-slot-value 1 name) crlf))
;(fact-slot-value 1 name)
;(> (fact-slot-value 1 men) (fact-slot-value 2 men))
I have tried removing some extra code just to see if I can access the previous user input but I'm still not getting an output.
(deftemplate company
(slot name)
(slot men)
(slot women)
(slot Asian)
(slot Black)
(slot Latinx)
(slot Indigenous)
(slot White)
(slot Other)
(slot <18)
(slot 18-20)
(slot 21-29)
(slot 30-39)
(slot 40+))
(deffacts demographics
(company (name Google)(men 0.669)(women 0.331)(Asian 0.428)(Black 0.088)(Latinx 0.088)(Indigenous 0.007)(White 0.445)(Other 0)(<18 0.02)(18-20 0.11)(21-29 0.59)(30-39 0.19)(40+ 0.07))
(company (name Apple)(men 0.652)(women 0.348)(Asian 0.279)(Black 0.094)(Latinx 0.148)(Indigenous 0.007)(White 0.438)(Other 0.032)(<18 0.01)(18-20 0.1)(21-29 0.57)(30-39 0.22)(40+ 0.06)))
(defrule begin => (assert (phase select-gender)))
(defrule menu (phase select-gender) =>
(printout t "Do you identify as a (1) man or (2) woman?: ") (assert (userinput (read)))(assert(phase select-ethnicity)))
(defrule menu2 (phase select-ethnicity) =>
(printout t "Do you identify as (1)Asian, (2)Black, (3)Latinx, (4)Indigenous, (5)White, or (6)Other?: ") (assert (userinput2 (read)))(assert(phase select-age)))
(defrule menu3 (phase select-age) =>
(printout t "You are age: (1)<18, (2)18-20, (3)20-30, (4)30-40, (5)40+?: ") (assert (userinput3 (read)))(assert(phase company-gender-men)))
(defrule get-company-by-gender-men
?phase <- (company-gender-men)
(userinput ?userinput)
=>
(retract ?phase)
(printout t ?userinput "can see user input"crlf))
(defrule get-company-by-gender-men
?phase <- (phase company-gender-men)
(userinput 1)
(company (name ?name) (men ?men1))
(company (men ?men2))
(test (> ?men1 ?men2))
=>
(retract ?phase)
(printout t ?name crlf))

I would like t o adjust my negative rule to accept any symbol and not just p and store that symbol in a variable

Hi i have created a clips program and in my defrule negative i am simulating a propositional law and would like the program to accept any symbol and not just a P symbol. I want the defrule to fire no matter the symbol that is there.
I have tried putting ?symbol instead of the P but that has not solved my problem just yet.
(deftemplate andprop (slot symbol1)(slot symbol2))
(deftemplate orprop (slot symbol1)(slot symbol2))
(deftemplate implies (multislot premise)(multislot implication))
(deftemplate sentence (multislot sent))
(defrule read-from-user
=>
(printout t "Please enter a sentence: Use ~ for not and => for implies please " crlf)
(bind ?response (readline))
(assert (sentence(sent ?response))))
(defrule negative
(sentence(sent "~(~P)"))
=>
(printout t "HI " crlf))
So i want the defrule negative to fire no matter the symbol that is in symbol so nt only if the symbol is a P
I'd suggest using the explode$ function to split the sentence into separate tokens.
CLIPS (6.31 2/3/18)
CLIPS>
(deftemplate andprop
(slot symbol1)
(slot symbol2))
CLIPS>
(deftemplate orprop
(slot symbol1)
(slot symbol2))
CLIPS>
(deftemplate implies
(multislot premise)
(multislot implication))
CLIPS>
(deftemplate sentence
(multislot sent))
CLIPS>
(defrule read-from-user
=>
(printout t "Please enter a sentence: Use ~ for not and => for implies please " crlf)
(bind ?response (readline))
(assert (sentence (sent (explode$ ?response)))))
CLIPS>
(defrule negative
(sentence (sent "~" "(" "~" ?symbol ")"))
=>
(printout t "HI " ?symbol crlf))
CLIPS> (run)
Please enter a sentence: Use ~ for not and => for implies please
~(~P)
HI P
CLIPS> (reset)
CLIPS> (run)
Please enter a sentence: Use ~ for not and => for implies please
~(~XYZ)
HI XYZ
CLIPS> (facts)
f-0 (initial-fact)
f-1 (sentence (sent "~" "(" "~" XYZ ")"))
For a total of 2 facts.
CLIPS>

Can I have a deptemplate inside a fact

(deftemplate andprop (slot symbol1)(slot symbol2))
(deftemplate orprop (slot symbol1)(slot symbol2))
(deftemplate implies (multislot premise)(multislot
implication))
(deftemplate sentence (multislot sent))
(defrule read-from-user
=>
(printout t "Please enter a value: " crlf)
(bind ?response (read))
(assert (sentence (sent andprop(symbol1 ?response)
(symbol2 ?response)))))
I am writing a CLIPS program to simulate the propsitional logic identities but when I try to run this piece of code i get the following
[EXPRNPSR3] Missing function declaration for 'symbol1'.
ERROR:
(defrule MAIN::read-from-user
=>
(printout t "Please enter a value: " crlf)
(bind ?response (read))
(assert (sentence (sent andprop (symbol1
You can set the value of a slot to another fact:
CLIPS (6.31 2/3/18)
CLIPS>
(deftemplate andprop
(slot symbol1)
(slot symbol2))
CLIPS>
(deftemplate orprop
(slot symbol1)
(slot symbol2))
CLIPS>
(deftemplate implies
(multislot premise)
(multislot implication))
CLIPS>
(deftemplate sentence
(multislot sent))
CLIPS>
(defrule read-from-user
=>
(printout t "Please enter a value: " crlf)
(bind ?response (read))
(bind ?sent (assert (andprop (symbol1 ?response)
(symbol2 ?response))))
(assert (sentence (sent ?sent))))
CLIPS> (run)
Please enter a value:
45678
CLIPS> (facts)
f-0 (initial-fact)
f-1 (andprop (symbol1 45678) (symbol2 45678))
f-2 (sentence (sent <Fact-1>))
For a total of 3 facts.
CLIPS>

Defining "anonymous" rules in CLIPS

I know that rules in CLIPS are usually given names using defrule. This rule is called rule1:
(deftemplate animal (slot species))
(deffacts animal
(animal (species dog)))
(defrule rule1
(animal (species ?name))
=>
(printout t ?name crlf))
(reset)
(run)
(exit)
;
But I still don't know whether it is necessary for the rules to be named. Is it possible to define a rule without giving it a name, like this?
(deftemplate animal (slot species))
(deffacts animal
(animal (species dog)))
(defrule
(animal (species ?name))
=>
(printout t ?name crlf))
(reset)
(run)
(exit)
;
From section 5 of the Basic Programming Guide:
(defrule <rule-name> [<comment>]
[<declaration>]
<conditional-element>*
=>
<action>*)
The rule name is required.
To dynamically generate a rule name, use the gensym* function which creates a unique symbol:
CLIPS>
(deffunction create-anonymous (?conditions ?actions)
(bind ?str (str-cat "(defrule " (gensym*) " "
?conditions " => " ?actions ")"))
(build ?str))
CLIPS> (deftemplate animal (slot species))
CLIPS>
(create-anonymous "(animal (species ?name))"
"(printout t ?name crlf)")
TRUE
CLIPS> (rules)
gen1
For a total of 1 defrule.
CLIPS> (ppdefrule gen1)
(defrule MAIN::gen1
(animal (species ?name))
=>
(printout t ?name crlf))
CLIPS>

Writing a defrule that extends a deftemplate

Suppose I have
(deftemplate a-template (slot A) (slot B))
and from an earlier rule I have A => C. I want to extend the template to
(deftemplate a-template (slot A) (slot B) (slot C))
How do you a write a rule that uses pre-existing rules to populate a fact template.
Thanks in advance
You can't redefine a deftemplate if any facts currently make use of that deftemplate:
CLIPS> (clear)
CLIPS> (deftemplate a-template (slot A) (slot B))
CLIPS> (deftemplate a-template (slot A) (slot B) (slot C))
CLIPS> (assert (a-template))
<Fact-1>
CLIPS> (deftemplate a-template (slot A) (slot B) (slot C) (slot D))
[CSTRCPSR4] Cannot redefine deftemplate a-template while it is in use.
ERROR:
(deftemplate MAIN::a-template
CLIPS>
However, if no such facts exist you can use introspection functions to examine the existing deftemplate in conjunction with the build function to create a new deftemplate:
CLIPS> (clear)
CLIPS>
(deffunction add-slot (?template ?slot)
(bind ?slots (deftemplate-slot-names ?template))
(if (member$ ?slot ?slots)
then
(return))
(bind ?build (str-cat "(deftemplate " ?template))
(progn$ (?s ?slots)
(if (deftemplate-slot-multip ?template ?s)
then
(bind ?build (str-cat ?build " (multislot " ?s ")"))
else
(bind ?build (str-cat ?build " (slot " ?s ")"))))
(bind ?build (str-cat ?build " (slot " ?slot ")"))
(bind ?build (str-cat ?build ")"))
(build ?build))
CLIPS> (deftemplate a-template (slot A) (slot B))
CLIPS> (ppdeftemplate a-template)
(deftemplate MAIN::a-template
(slot A)
(slot B))
CLIPS> (add-slot a-template C)
TRUE
CLIPS> (ppdeftemplate a-template)
(deftemplate MAIN::a-template
(slot A)
(slot B)
(slot C))
CLIPS>
If you wanted to redefine a template with existing facts, you'd need to save the existing facts using the save-facts function, retract all of them, redefine the template, and then reload the saved facts. This could cause rules matching the existing facts to be placed on the agenda if they had already executed.

Resources