How to retrieve a handle to facts inside a deffacts construct? - clips

As described by the question, I would somehow try to get an handle to a fact within a deffacts construct. The problem arises because I don't want to redefine the same thing several times in WM (since set-fact-duplication is true) and because I use a structured deftemplate in which a field is a FACT_ADDRESS.

You can't bind a fact address within a deffacts construct. What I would suggest instead is to use a symbolic link between the facts. In your case, if the name of the tourism-type, tourism-resort, and hotel facts is unique among facts of each type, you could use that slot as the symbolic link:
(deftemplate tourism-type
(slot name)
(slot score))
(deftemplate hotel
(slot name)
(slot tr)
(slot stars)
(slot price-per-night))
(deftemplate tourism-resort
(slot name)
(slot region)
(multislot type))
(deffacts the-tourism-type-list
(tourism-type (name culturale) (score 3))
(tourism-type (name enogastronomico) (score 4)))
(deffacts the-tourism-resort-list
(tourism-resort
(name Venezia)
(region Veneto)
(type culturale enogastronomico)))
(deffacts the-hotels-list
(hotel
(name hotel1)
(tr Venezia)
(stars 3)
(price-per-night 100)))
In your rules, you can then use the symbolic link to retrieve the linked fact:
(defrule food-and-wine-hotels
(hotel (name ?hotel)
(tr ?tr-name))
(tourism-resort
(name ?tr-name)
(type $? enogastronomico $?))
=>
(printout t ?hotel crlf))

Related

How to retrive facts asserted by a rule having particular name?

I have certain template defined as follows:
(deftemplate action
(slot name)
(slot field)
(slot value))
I have other rules which will use other facts to assert the action fact.
Now I want to retrieve only the fact with template action.
For now, I am using find-fact to retrieve, but here I have to use query which I do not want to provide.
(find-fact ((?fact action)) (= (str-compare ?fact:name 'Action1') 0))
I want all facts with template action and do not want to write a loop over all names with Action1, Action2 etc..
Thank you in advance.
CLIPS (6.31 4/1/19)
CLIPS>
(deftemplate action
(slot name)
(slot field)
(slot value))
CLIPS>
(deffacts actions
(action (name Action1) (field x) (value 3))
(action (name Action2) (field y) (value 4))
(action (name Action3) (field z) (value 5)))
CLIPS>
(defrule find-Action1
(action (name Action1))
=>)
CLIPS> (reset)
CLIPS> (agenda)
0 find-Action1: f-1
For a total of 1 activation.
CLIPS> (facts)
f-0 (initial-fact)
f-1 (action (name Action1) (field x) (value 3))
f-2 (action (name Action2) (field y) (value 4))
f-3 (action (name Action3) (field z) (value 5))
For a total of 4 facts.
CLIPS>

correlation between deffunctions and defrules 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>

wxclips: [MSGFUN1] and [MSGPASS2] while trying to use instances

I'm trying to run classes in wxclips but its not working anyidea what's wrong.
Note this code is from tutorials and it should be working but it isn't
> CLIPS> (defclass A (is-a USER) (role concrete) (slot foo (create-accessor write)) (slot bar))
> CLIPS> (make-instance a of A (foo 36)) [a] CLIPS> (make-instance b of A (bar 45)) [MSGFUN1]
> No applicable primary message-handlers found for put-bar. FALSE CLIPS>
> CLIPS>(defclass person (is-a USER) (multislot full-name) (role concrete) (slot gender (allowed-symbols male female)) (slot age))
> CLIPS>(definstances people (mike of person(gender "male")(age 24)))
> CLIPS>(send [mike] get-gender)
[MSGPASS2] No such instance mike in function send
You need to create slot accessors for any slot you want to read or write and instances from definstances are not created until you issue a (reset) command.
CLIPS> (defclass A (is-a USER) (role concrete) (slot foo(create-accessor write)) (slot bar (create-accessor write)))
CLIPS> (make-instance a of A (foo 36))
[a]
CLIPS> (make-instance b of A (bar 45))
[b]
CLIPS> (defclass person (is-a USER) (multislot full-name) (role concrete) (slot gender (allowed-symbols male female) (create-accessor read-write)) (slot age (create-accessor read-write)))
CLIPS> (definstances people (mike of person(gender "male")(age 24)))
CLIPS> (reset)
CLIPS> (send [mike] get-gender)
"male"

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.

Create rules in CLIPS to move from unknown to known person facts

Assume that you are given a set of 'person' facts that are defined according to the following construct:
(deftemplate person (slot name) (slot sex) (allowed-values male female) (multislot children))
Write rules to do the following:
Create a fact of the form (unknown-person ) for each name that appears in the children multislot of a person fact but not in the name slot of any person fact (it is assumed that no two people have the same name)
For each fact of the form (unknown-person ) ask the user for the sex of the person, retract the fact and assert a new fact of the form (unknown-person ).
For each fact of the form (unknown-person ), retract the fact and create a new person fact for the person (it is assumed that the person has no children).
Your rules should do data validation to ensure that only an allowed value for is supplied by the user
Define the template in CLIPS:
(deftemplate person
(slot name)
(slot sex)
(slot gender (allowed-values male female))
(multislot children))
Start with the unknown-person creation (caveat: this may not be completely correct as it still creates a person without checking to see if they exist).
(defrule childrencataloguer "First layer of unknown person resolution"
(person (children $?ch))
=>
(progn$ (?term ?ch)
(assert (unknown-person ?term))
))
Deal with the caveat above
(defrule removeunknownswithpersonsalready
(person (name ?n))
?up <-(unknown-person ?n)
=>
(retract ?up))
Now, get the gender:
(defrule getgender
?up-nogen <-(unknown-person ?n)
=>
(retract ?up-nogen)
(printout t crlf "Please enter male or female to indicate " ?n "'s gender" crlf )
(assert (unknown-person ?n (read)))
)
There are other ways you can do the gender confirmation, I would have liked to use the deftemplate itself, so that the allowed-values would have fed into the validation. But I don't know how yet.
(assert (gender male))
(assert (gender female))
Now, do validation:
(defrule checkgender
?p <- (unknown-person ?n ?s)
(not (gender ?s))
=>
(retract ?p)
(assert (unknown-person ?n))
)
Finally, graduate from unknown
(defrule graduatefromunknown
(declare (salience -10))
?up <- (unknown-person ?n ?s)
=>
(retract ?up)
(assert (person (name ?n) (sex ?s)))
)

Resources