问题
Is it possible to cause CLIPS to re-evaluate the value of a global variable in a defrule? I have this:
(defrule encourage "Do we have a GPA higher than 3.7?"
(test (> (gpa) 3.7))
=>
(printout t "Keep up the excellent work!" crlf))
gpa is function that calculates and returns a number based on two global variables (grade points and number of credits). I read somewhere that changes to global variables do not invoke pattern matching. How do I go about forcing this? I want to print that string every time I do (run) as long as the GPA is higher than 3.7.
回答1:
Don't attempt to use global variables or function calls in this manner. First, global variables are specifically designed to not trigger pattern matching. Second, it would take a bit of magic for CLIPS to know when a function call needs to be reevaluated as there are any number of changes which could cause a function to return a different value, not just changes to globals. If you want a particular piece of information to trigger pattern matching, then stick it in a fact or instance. It will make your code easier to understand if you parameterize the function calls and bind the values to be used as arguments in the conditions of the rule.
CLIPS> (clear)
CLIPS>
(deffunction gpa (?grade-points ?number-of-credits)
(/ ?grade-points ?number-of-credits))
CLIPS>
(defrule encourage "Do we have a GPA higher than 3.7?"
(grade-points ?gp)
(number-of-credits ?noc)
(test (> (gpa ?gp ?noc) 3.7))
=>
(printout t "Keep up the excellent work!" crlf))
CLIPS> (assert (grade-points 35) (number-of-credits 10))
<Fact-2>
CLIPS> (agenda)
CLIPS> (facts)
f-0 (initial-fact)
f-1 (grade-points 35)
f-2 (number-of-credits 10)
For a total of 3 facts.
CLIPS> (retract 1)
CLIPS> (assert (grade-points 38))
<Fact-3>
CLIPS> (agenda)
0 encourage: f-3,f-2
For a total of 1 activation.
CLIPS>
Alternately, you can use the fact query functions to iterate over a group of facts to dynamically compute the gpa based on facts rather than globals. Each time you modify one of these facts (add or remove), you can also assert a fact indicating the gpa needs to be rechecked to trigger the encourage rule.
CLIPS> (clear)
CLIPS>
(deftemplate grade
(slot class)
(slot grade-points)
(slot credits))
CLIPS>
(deffunction gpa ()
(bind ?grade-points 0)
(bind ?credits 0)
(do-for-all-facts ((?g grade)) TRUE
(bind ?grade-points (+ ?grade-points ?g:grade-points))
(bind ?credits (+ ?credits ?g:credits)))
(if (= ?credits 0)
then 0
else (/ ?grade-points ?credits)))
CLIPS>
(defrule encourage
?f <- (check-gpa)
=>
(retract ?f)
(if (> (gpa) 3.7)
then
(printout t "Keep up the excellent work!" crlf)))
CLIPS> (gpa)
0
CLIPS> (assert (check-gpa))
<Fact-1>
CLIPS> (run)
CLIPS> (assert (grade (class Algebra) (grade-points 12) (credits 3)))
<Fact-2>
CLIPS> (gpa)
4.0
CLIPS> (assert (check-gpa))
<Fact-3>
CLIPS> (run)
Keep up the excellent work!
CLIPS> (assert (grade (class History) (grade-points 6) (credits 2)))
<Fact-4>
CLIPS> (gpa)
3.6
CLIPS> (assert (check-gpa))
<Fact-5>
CLIPS> (run)
CLIPS> (assert (grade (class Science) (grade-points 12) (credits 3)))
<Fact-6>
CLIPS> (gpa)
3.75
CLIPS> (assert (check-gpa))
<Fact-7>
CLIPS> (run)
Keep up the excellent work!
CLIPS>
来源:https://stackoverflow.com/questions/30017688/clips-forcing-a-rule-to-re-evaluate-the-value-of-a-global-variable