Clips passing a multivalued variable to a deffunction - rules

I am currently writing a program that will simulate the propositional laws. I have received a function my-test to determine whether certain characters are in a string and i works fine if i pass only a single slot variable but it won#t accept a multislot/multi value variable.
I have go the code working i f a pass for example ?sigle but if I try and pass $?symbol to the program it says that it is epecting a string or symbol.
(deftemplate sentence (multislot sent))
(defrule read-from-user
=>
(bind ?response "")
(printout t "Please enter a sentence: Use ~ for not and => for implies, or(v) and and(^) please. For predicates use { and } Example exists{richard}" crlf)
(bind ?response (explode$ (readline)))
(bind ?response (replace-member$ ?response "(" (sym-cat "(")))
(bind ?response (replace-member$ ?response ")" (sym-cat ")")))
(bind ?response (replace-member$ ?response "~" (sym-cat "~")))
(bind ?response (replace-member$ ?response "v" (sym-cat "v")))
(bind ?response (replace-member$ ?response "=>" (sym-cat "=>")))
(bind ?response (replace-member$ ?response "^" (sym-cat "^")))
(bind ?response (replace-member$ ?response "[" (sym-cat "[")))
(bind ?response (replace-member$ ?response "]" (sym-cat "]")))
(bind ?response (replace-member$ ?response "{" (sym-cat "{")))
(bind ?response (replace-member$ ?response "}" (sym-cat "}")))
(assert (sentence (sent ?response))))
(deffunction my-test ($?symbol) (not (or (str-index "^" ?symbol) (str-index "v" ?symbol))))
(defrule negative
(sentence (sent $?before "~" "(" "~" $?symbol ")" $?after))
(test (my-test $?symbol))
=>
(assert (sentence (sent $?before $?symbol $?after))))
(run)
Please enter a sentence: Use ~ for not and => for implies, or(v) and and(^) please. For predicates use { and } Example exists{richard}
~(~P v Q)
[ARGACCES2] Function 'str-index' expected argument #2 to be of type symbol, string, or instance name.
[PRCCODE4] Execution halted during the actions of deffunction 'my-test'.
This is the error i receive when i run the program i have a feeling that i need to do a conversio but am not quite sure what exctly needs to be done. Thx for the help

If you're passing multiple symbols to the my-test function to test, you need to iterate over them using the foreach function.
CLIPS (6.31 4/1/19)
CLIPS> (deftemplate sentence (multislot sent))
CLIPS>
(defrule read-from-user
=>
(bind ?response "")
(printout t "Please enter a sentence: Use ~ for not and => for implies, or(v) and and(^) please. For predicates use { and } Example exists{richard}" crlf)
(bind ?response (explode$ (readline)))
(bind ?response (replace-member$ ?response "(" (sym-cat "(")))
(bind ?response (replace-member$ ?response ")" (sym-cat ")")))
(bind ?response (replace-member$ ?response "~" (sym-cat "~")))
(bind ?response (replace-member$ ?response "v" (sym-cat "v")))
(bind ?response (replace-member$ ?response "=>" (sym-cat "=>")))
(bind ?response (replace-member$ ?response "^" (sym-cat "^")))
(bind ?response (replace-member$ ?response "[" (sym-cat "[")))
(bind ?response (replace-member$ ?response "]" (sym-cat "]")))
(bind ?response (replace-member$ ?response "{" (sym-cat "{")))
(bind ?response (replace-member$ ?response "}" (sym-cat "}")))
(assert (sentence (sent ?response))))
CLIPS>
(deffunction my-test (?symbols)
(foreach ?s ?symbols
(if (or (str-index "^" ?s) (str-index "v" ?s))
then (return FALSE)))
(return TRUE))
CLIPS>
(defrule negative
(sentence (sent $?before "~" "(" "~" $?symbol ")" $?after))
(test (my-test $?symbol))
=>
(assert (sentence (sent $?before $?symbol $?after))))
CLIPS> (run)
Please enter a sentence: Use ~ for not and => for implies, or(v) and and(^) please. For predicates use { and } Example exists{richard}
~(~P v Q)
CLIPS>

Related

asserting string in clips

I am trying to assert the value of name into a variable but when i assert it the value is coming in quotes and also with an extra space at the end.
(defrule discount_amt_group
(exists (Student (age 14)(marks ?q&:(> ?q 40))))
=>
(bind ?name "")
(do-for-all-facts ((?p Student))
(or (eq ?p:marks 80)
(eq ?p:marks 75)
(eq ?p:marks 90))
(bind ?name (str-cat ?name ?p:name " "))
(bind ?totalMarks (+ ?totalMarks ?p:marks)))
(assert (StudOut(names ?name)))
the expected value will be (name Harry Ron Ginger) but now its coming as (name "Harry Ron Ginger ")
please suggest.
Represent the names as a multifield value rather than a string. You can use the create$ function to initially create an empty multifield value and then again to append values to it.
CLIPS (6.31 6/12/19)
CLIPS>
(deftemplate Student
(slot name)
(slot age)
(slot marks))
CLIPS>
(deftemplate StudOut
(multislot names)
(slot totalMarks))
CLIPS>
(deffacts Students
(Student (name Harry) (age 14) (marks 80))
(Student (name Ron) (age 15) (marks 75))
(Student (name Ginger) (age 14) (marks 90))
(Student (name Sally) (age 12) (marks 95)))
CLIPS>
(defrule discount_amt_group
(exists (Student (age 14)(marks ?q&:(> ?q 40))))
=>
(bind ?name (create$))
(bind ?totalMarks 0)
(do-for-all-facts ((?p Student))
(or (eq ?p:marks 80)
(eq ?p:marks 75)
(eq ?p:marks 90))
(bind ?name (create$ ?name ?p:name))
(bind ?totalMarks (+ ?totalMarks ?p:marks)))
(assert (StudOut (names ?name)
(totalMarks ?totalMarks))))
CLIPS> (reset)
CLIPS> (run)
CLIPS> (facts)
f-0 (initial-fact)
f-1 (Student (name Harry) (age 14) (marks 80))
f-2 (Student (name Ron) (age 15) (marks 75))
f-3 (Student (name Ginger) (age 14) (marks 90))
f-4 (Student (name Sally) (age 12) (marks 95))
f-5 (StudOut (names Harry Ron Ginger) (totalMarks 245))
For a total of 6 facts.
CLIPS>

Cant implement function on Bind in CLIPS

(deffunction slabV10071 ( ?totalQuantity ?quantityBuilder )
(bind ?promoQuantities (integer (/ ?totalQuantity 6)))
if(>= ?totalQuantity 12) then
(assert(Output (promoId V10071)(promotionTypeCode 1)(productIds 3089 2264 2090 )(quantities ?quantityBuilder)(uom EA)(promoQuantities ?promoQuantities)(values 1666.6666666)(rewardId 3089,2264,2090)(repeatingRange 1)(proRata N)(exclusionFlag 1)(sequenceNumber 3335)(effectiveFrom 2020-05-27)))
(return))(bind ?promoQuantities (integer (/ ?totalQuantity 12)))
if(>= ?totalQuantity 6) then
(assert(Output (promoId V10071)(promotionTypeCode 1)(productIds 3089 2264 2090 )(quantities ?quantityBuilder)(uom EA)(promoQuantities ?promoQuantities)(values 1700)(rewardId 3089,2264,2090)(repeatingRange 1)(proRata N)(exclusionFlag 1)(sequenceNumber 3335)(effectiveFrom 2020-05-27)))
(return)))
(defrule V10071
(exists (Product(productId 3089)(quantity ?q&:(> ?q 1))(date ?orderDate&:(<= 20200527 ?orderDate 20201231))))
=>
(bind ?totalQuantity 0)
(bind ?quantityBuilder "")
(do-for-all-facts ((?p Product))
(or (eq ?p:productId 3089)
(eq ?p:productId 2264)
(eq ?p:productId 2090)
)
(bind (str-cat ?quantitybuilder ?p:quantity " " ))
(bind ?totalQuantity (+ ?totalQuantity ?p:quantity)))
(if(>= ?totalQuantity 1) then
(slabV10071 ?totalQuantity ?quantityBuilder)))
This is the code. The slabV10071 function is working fine. But In the rule im getting the error
[PRNTUTIL2] Syntax Error: Check appropriate syntax for bind function.
[PRNTUTIL2] Syntax Error: Check appropriate syntax for fact-set query function.
Please help.
The error message shows you the position in your rule where the error is occurring:
ERROR:
(defrule MAIN::V10071
(exists
(Product (productId 3089) (quantity ?q&:(> ?q 1)) (date ?orderDate&:(<= 20200527 ?orderDate 20201231))))
=>
(bind ?totalQuantity 0)
(bind ?quantityBuilder "")
(do-for-all-facts ((?p Product))
(or (eq ?p:productId 3089) (eq ?p:productId 2264) (eq ?p:productId 2090))
(bind(
This is the line of code causing the error:
(bind (str-cat ?quantitybuilder ?p:quantity " " ))
You're not providing a variable to which the function call will be bound. This is probably what you want:
(bind ?quantitybuilder (str-cat ?quantitybuilder ?p:quantity " " ))

CLIPS Error: Illegal use of the module specifier when defrule

I want to define some module-rules to assert module-facts, and then batch get a group of facts list by get-fact-list, but an error occurred!
CLIPS (6.31 6/12/19)
CLIPS> (defmodule M)
CLIPS> (deftemplate M::T (slot k1))
CLIPS> (defrule M::T (testvalue 1) => (assert (M::T (k1 "v1"))))
[MODULDEF1] Illegal use of the module specifier.
ERROR:
(defrule M::T
(testvalue 1)
=>
(assert (M::T
CLIPS>
expected:
CLIPS> (defmodule M)
CLIPS> (deftemplate M::T (slot k1))
CLIPS> (defrule M::T (testvalue 1) => (assert (M::T (k1 "v1"))))
CLIPS> (assert (testvalue 1))
CLIPS> (get-fact-list M)
;; return the facts that M::rulexx assert
Why is the sytax error? How can I do it for the defrule of module?
Don't use M::T in your assert command. Since the defrule is contained in module M, all deftemplates visible to M can be referenced without using a module specifier.
CLIPS (6.31 6/12/19)
CLIPS> (defmodule M)
CLIPS> (deftemplate M::T (slot k1))
CLIPS> (defrule M::T (testvalue 1) => (assert (T (k1 "v1"))))
CLIPS> (assert (testvalue 1))
<Fact-1>
CLIPS> (get-fact-list M)
(<Fact-1>)
CLIPS>

CLIPS Is there a function similar to contains in C#?

Hi i m writing a program that will simulate the propositional laws. I would like to ensure that certain characters are not contained within my variables. Is there a easy function to do this.
I currently have it working if my variable is only a single character but would like to make it work with a multi-slot variable.
(deftemplate sentence (multislot sent))
(defrule read-from-user
=>
(bind ?response "")
(printout t "Please enter a sentence: Use ~ for not and => for implies, or(v) and and(^) please. For predicates use { and } Example exists{richard}" crlf)
(bind ?response (explode$ (readline)))
(bind ?response (replace-member$ ?response "(" (sym-cat "(")))
(bind ?response (replace-member$ ?response ")" (sym-cat ")")))
(bind ?response (replace-member$ ?response "~" (sym-cat "~")))
(bind ?response (replace-member$ ?response "v" (sym-cat "v")))
(bind ?response (replace-member$ ?response "=>" (sym-cat "=>")))
(bind ?response (replace-member$ ?response "^" (sym-cat "^")))
(bind ?response (replace-member$ ?response "[" (sym-cat "[")))
(bind ?response (replace-member$ ?response "]" (sym-cat "]")))
(bind ?response (replace-member$ ?response "{" (sym-cat "{")))
(bind ?response (replace-member$ ?response "}" (sym-cat "}")))
(assert (sentence (sent ?response))))
(defrule negative
(sentence (sent $?before "~" "(" "~" ?symbol ")" $?after))
(test (neq ?symbol "~" "(" ")" "=" "^" "v"))
=>
(assert (sentence (sent $?before $?symbol $?after))))
This piece of code works for single characters but i know what to make the
?Symbol into $?symbol and still check that none of the character (,),~,= etc are in ?$symbol.
So if there is any similar function to compare in C# that i can use her? thx guys
Use the str-index function to determine if a sequence of characters is contained within a string:
CLIPS (6.31 4/4/19)
CLIPS> (str-index "^" "abc")
FALSE
CLIPS> (str-index "^" "ab^c")
3
CLIPS>

Recursive call to a rule

I have this rule that fires thousands of other same rule:
(defrule calculate-temperature
?zone <- (object (is-a ZONE) (id ?id-zone) (dew-temperature ?dew-temperature) (delta-R ?delta-R))
(process-action (is cooling))
=>
(bind ?supply-temperature (+ ?delta-R ?dew-temperature))
(modify-instance ?zone (supply-temperature ?supply-temperature))
(printout ?*debug-print* "supply-temperature:", ?supply-temperature crlf))
What I want to do is to modify my zone's supply-temperature when I can calculate it, i.e. when inside zone are defined delta-R and dew-temperature.
But the modification of the object keeps on firing in a recursice neverendless cycle.
What are best practices to avoid these annoying loops, please?
Thank you
Nicola
By itself this rule doesn't loop:
CLIPS> (clear)
CLIPS>
(defclass ZONE
(is-a USER)
(slot id)
(slot dew-temperature)
(slot supply-temperature)
(slot delta-R))
CLIPS>
(definstances start-instances
(z1 of ZONE (id 1) (dew-temperature 100) (delta-R 10)))
CLIPS>
(deftemplate process-action
(slot is))
CLIPS>
(deffacts start-facts
(process-action (is cooling)))
CLIPS> (defglobal ?*debug-print* = nil)
CLIPS>
(defrule calculate-temperature
?zone <- (object (is-a ZONE)
(id ?id-zone)
(dew-temperature ?dew-temperature)
(delta-R ?delta-R))
(process-action (is cooling))
=>
(bind ?supply-temperature (+ ?delta-R ?dew-temperature))
(modify-instance ?zone (supply-temperature ?supply-temperature))
(printout ?*debug-print* "supply-temperature:", ?supply-temperature crlf))
CLIPS> (watch slots)
CLIPS> (reset)
::= local slot id in instance z1 <- 1
::= local slot dew-temperature in instance z1 <- 100
::= local slot delta-R in instance z1 <- 10
::= local slot supply-temperature in instance z1 <- nil
CLIPS> (run)
::= local slot supply-temperature in instance z1 <- 110
CLIPS>
So it's the interactions between your rules that are causing the loop.
There are three general techniques to prevent rule looping. First, you can remove one of the facts/instances matching the conditions of the rule. For example, the process-action fact:
(defrule calculate-temperature
?zone <- (object (is-a ZONE)
(id ?id-zone)
(dew-temperature ?dew-temperature)
(delta-R ?delta-R))
?p <- (process-action (is cooling))
=>
(retract ?p)
(bind ?supply-temperature (+ ?delta-R ?dew-temperature))
(modify-instance ?zone (supply-temperature ?supply-temperature))
(printout ?*debug-print* "supply-temperature:", ?supply-temperature crlf))
Second, you can modify a fact/instance slot value to prevent a pattern from matching. For example, delta-R:
(defrule calculate-temperature
?zone <- (object (is-a ZONE)
(id ?id-zone)
(dew-temperature ?dew-temperature)
(delta-R ?delta-R&~0))
(process-action (is cooling))
=>
(bind ?supply-temperature (+ ?delta-R ?dew-temperature))
(modify-instance ?zone (supply-temperature ?supply-temperature) (delta-R 0))
(printout ?*debug-print* "supply-temperature:", ?supply-temperature crlf))
Third (and this is only applicable for object pattern matching), rules are only triggered by changes to slots that are explicitly matched in the conditions of the rules. So if you want changes to delta-R to trigger the rule, but not changes to dew-temperature, you'd write the rule like this:
(defrule calculate-temperature
?zone <- (object (is-a ZONE)
(id ?id-zone)
(delta-R ?delta-R))
(process-action (is cooling))
=>
(bind ?supply-temperature (+ ?delta-R (send ?zone get-dew-temperature)))
(modify-instance ?zone (supply-temperature ?supply-temperature))
(printout ?*debug-print* "supply-temperature:", ?supply-temperature crlf))

Resources