home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
kermit.columbia.edu
/
kermit.columbia.edu.tar
/
kermit.columbia.edu
/
ckscripts
/
rule-engine
< prev
next >
Wrap
Lisp/Scheme
|
2004-05-18
|
8KB
|
376 lines
# From: "Dat Nguyen" <thucdat@hotmail.com>
# Subject: Module rule-engine
# Date: Wed, 19 May 2004 01:16:37 -0400
#
# Animal Taxonomy is a favorite subject of specialized rule-based programming
# languages. With some creative construction, C-Kermit can solve that problem
# in the same manner. The cheetah.kr script exposes the same look and feel of
# many rule-based programs. Many configuration problems in computer
# administration and network should be solvable similarly, provided the rule
# set can be identified.
#
# This demonstration comes in two modules: rule-engine and cheetah.
# To run the demonstration, tell Kermit to TAKE the cheetah module.
#
# Here is rule-engine:
define say {
echo \%1
return 1
}
define askContent {
local \%v
ask \%v {[\%1]: }
_asg \%1 \%v
return \%1
}
define askYesNo {
local ans
while true {
ask ans {\%1 (y|n): }
if \find(y,\m(ans)) return 1
if \find(n,\m(ans)) return 0
}
}
define askANumber {
local \%n
while true {
echo Enter a Value
ask \%n {[\%1]: }
if numeric \%n return \%n
}
}
define disableRule {
local \%i
for \%i 1 \v(argc)-1 1 {
asg RuleDatabase \m(RuleDatabase)\&_[\%i]|
incr RuleNumber
}
}
define enableRule {
local \%i
for \%i 1 \v(argc)-1 1 {
asg RuleDatabase \freplace(\m(RuleDatabase),|\&_[\%i]|,|)
decr RuleNumber
}
}
define availableRule {
if \find(\%1,\m(RuleDatabase)) return 0
disableRule {\%1}
return 1
}
define eligibleRule {
(! \find(\%1,\m(RuleDatabase)))
}
define clearRuleDatabase {
asg RuleDatabase |
(setq RuleNumber 0)
}
define addFact {
local \%i
for \%i 1 \v(argc)-1 1 {
if \find(\&_[\%i],\m(FactDatabase)) continue
asg FactDatabase \m(FactDatabase)\&_[\%i]|
incr FactNumber
}
# showFact
}
define addATrueFact {
# \%1 Name of the Boolean fact
# \%2 Value of Boolean fact
# Overwrite previous value
local \%s \%w \%f
asg \%s \fword(\%1,1)_\fword(\%1,2)
asg \%w \freplace(\%1,{\fword(\%1,1) \fword(\%1,2) })
_asg \%s |\%w|
addFact {\%s}
return 1
}
define addAlsoTrueFact {
local \%s \%w \%f
asg \%s \fword(\%1,1)_\fword(\%1,2)_also
asg \%w \freplace(\%1,{\fword(\%1,1) \fword(\%1,2) })
_asg \%s \m(\%s)|\%w|
addFact {\%s}
return 1
}
define addTrueFact {
# add and initialize with True
_asg \%1 1
addFact {\%1}
}
define addFalseFact {
_asg \%1 0
# add and initialize with False
addFact {\%1}
}
define addValueFact {
if \find(\%1,\m(FactDatabase)) return \m(\%1)
_asg \%1 \fsexpr(askANumber '(\%1))
addFact {\%1}
return \m(\%1)
}
define addcontentFact {
if \find(\%1,\m(FactDatabase)) return \m(\%1)
_asg \%1 \fsexpr(askContent '(\%1))
addFact {\%1}
return \m(\%1)
}
define removeFact {
local \%i
for \%i 1 \v(argc)-1 1 {
asg FactDatabase \freplace(\m(FactDatabase),|\&_[\%i]|,|)
decr FactNumber
}
# showFact
}
define isItTrueThat {
# Use for fact that can have only one of two possible value.
# a buble can be either ON of OFF
local \%s \%w \%f
asg \%s \fword(\%1,1)_\fword(\%1,2)
asg \%w \freplace(\%1,{\fword(\%1,1) \fword(\%1,2) })
asg \%f \find(\%s,\m(FactDatabase))
if \%f {
# term in factdatabase
if \find(|\%w|,\m(\%s)) return 1
return 0
} else {
# term not in factdatabase
local \%a
asg \%a \fsexpr(askYesNo '(\%1))
if \%a {
_asg \%s |\%w|
# save fact only when not in database before
if not \%f addFact {\%s}
}
return \%a
}
}
define isTrueFact {
# This responds with the content of the fact (True or False)
if \find(\%1,\m(FactDatabase)) return \m(\%1)
_asg \%1 \fsexpr(askYesNo '(\%1))
addFact {\%1}
return \m(\%1)
}
define gotFact {
# This gives user a chance to create a state fact with y(yes) or n(no)
if \find(\%1,\m(FactDatabase)) return 1
echo \%1
local \%a
asg \%a \fexec(askYesNo)
if \%a { # yes, create fact
addFact {\%1}
}
return \%a
}
define hasFact {
# This does not expect user to respond
(\find(\%1,\m(FactDatabase)))
}
define anyFact {
(FactNumber)
}
define removeAllFact {
asg FactDatabase |
(setq FactNumber 0)
}
define showFact {
show mac FactDatabase
show mac FactNumber
}
define addGoal {
local \%i
for \%i 1 \v(argc)-1 1 {
asg GoalDatabase \m(GoalDatabase)\&_[\%i]|
incr GoalNumber
}
# showGoal
}
define removeGoal {
local \%i
for \%i 1 \v(argc)-1 1 {
asg GoalDatabase \freplace(\m(GoalDatabase),|\&_[\%i]|,|)
decr GoalNumber
}
# showGoal
}
define allGoalDone {
(! GoalNumber)
}
define hasGoal {
(\find(\%1,\m(GoalDatabase)))
}
define removeAllGoal {
asg GoalDatabase |
(setq GoalNumber 0)
}
define showGoal {
show mac GoalDatabase
show mac GoalNumber
}
define fireRule {
local \&e[] \%n \%i \%f
asg \%n \fsplit(\%1,&e,{ })
while true {
for \%i 1 \%n 1 {
if define \m(\&e[\%i]) {
asg \%f \fexec(\&e[\%i])
# if rule was fired, reevaluate all rules
if > \%f 0 {
asg firedRules \m(firedRules)|\&e[\%i]
echo \&e[\%i] was fired
if = 2 \%f END
break
}
}
}
if not \%f break # no rule was fired
if = 1 \fexec(allGoalDone) break # all goals achieved
}
echo
echo {That's all there is}
echo
}
define rule_sample {
(if (hasGoal 'Goal_xxx)
(if (hasFact 'Fact_yyy)
(if (not (hasGoal 'Goal_zzz))
(.
(removeGoal 'Goal_xxx) # Goal achieved
(removeFact 'Fact_yyy) # Fact changed
(addGoal 'Fact_www) # New goal
(addFact 'Fact_yyy) # New fact
(1)
)
(0)
)
(0)
)
(0)
)
}
define mutual_exclude {
local \%i \%s
asg \%s +
for \%i 1 \v(argc)-1 1 {
asg \%s \%s\&_[\%i]+
}
_asg \v(macro)_term \m(\v(macro)_term)|\%s
}
define addThisFact {
asg allTheFacts \m(allTheFacts)|\%1
registerThisFact {\%1} 1 0
}
define excludeThisFact {
asg allTheFacts \freplace(\m(allTheFacts),|\%1|,|)
registerThisFact {\%1} 0 1
}
define showAllFacts {
local \%i \&w[]
for \%i 1 \fsplit(\m(allTheFacts),&w,|) 1 {
echo \&w[\%i]
}
}
define clearAllFacts {
asg allTheFacts
}
define registerThisFact {
local \%i \%k \%n \&w[] \%f
asg \%n \fsplit(\m(mutual_exclude_term),&w,|)
if \%n {
local \%m \&e[]
# There is mutual exclusive fact
asg \%f \farraylook(^+\%1+*,&w)
if > \%f 0 {
asg \%m \fsplit(\&w[\%f],&e,{+})
# This is a mutual exclusive fact
if \%2 {
# This is a true fact, turn off all others
for \%i 1 \%m 1 {
_asg \&e[\%i] \%3
}
} else {
# This is a false fact, turn off only for boolean fact
if = 2 \%m {
# This is a boolean fact
for \%i 1 \%m 1 {
_asg \&e[\%i] \%3
}
}
}
}
}
_asg \%1 \%2
}
define consultUser {
asg consult_user 1
}
define donotConsultUser {
asg consult_user 0
}
donotConsultUser
define isThisFactTrue {
if define \m(\%1) return \m(\%1)
local \%a
if == \m(consult_user) 1 {
asg \%a \fsexpr(askYesNo '(\%1))
} else {
asg \%a 0
}
if \find(+\%1+,\m(mutual_exclude_term)) {
# term with mutual exclusion
if = 1 \%a {
addThisFact {\%1}
} else {
excludeThisFact {\%1}
}
} else {
# term withOUT mutual exclusion
_asg \%1 \%a
}
return \%a
}
# \farraylook(oofa*,&a)