CLIPS规则中模板变量全匹配校验及规则失效问题排查
CLIPS规则匹配问题修复方案
问题描述
需要实现校验zakaznik模板所有变量与mobily模板完全相等:
- 匹配时输出
Telefon je na sklade: [品牌] [型号] - 不匹配时输出
Bohuzial zadany telefon nemame na sklade
但编写规则后,即便变量完全匹配,也仅最后一条telefon_nie_je_na_sklade规则生效。
问题根源
- 数据类型不匹配:使用
read函数读取输入时默认返回字符串类型,但zakaznik模板的多个槽(如znacka为SYMBOL、interna_pamat为INTEGER、uhlopriecka为FLOAT)需要对应数据类型,直接断言会导致与mobily事实的槽值类型不兼容,无法触发匹配规则。 - 规则重复触发风险:未处理
zakaznik事实,规则会持续触发,加上CLIPS默认的LEX优先级(后定义规则优先级更高),进一步加剧问题。
修复方案
1. 输入数据类型转换
在读取用户输入后,将字符串转换为模板要求的数据类型:
- SYMBOL类型槽:用
(symbol-value)转换 - INTEGER类型槽:用
(integer)转换 - FLOAT类型槽:用
(float)转换 - STRING类型槽(如
model)无需转换
2. 绑定并移除触发事实
在规则条件中绑定zakaznik事实,动作中移除该事实并停止推理,避免规则重复触发。
修复后的完整代码
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Sablony pre vstupy ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (deftemplate mobily (slot znacka (type SYMBOL)) (slot model (type STRING) ) (slot rozlisenie (type SYMBOL) (allowed-values HD FULL_HD Q_HD)) (slot SD_Karta (type SYMBOL) (allowed-values ano nie)) (slot interna_pamat (type INTEGER) (range 32 512)) (slot operacny_system (type SYMBOL) (allowed-values iOS android ine)) (slot uhlopriecka (type FLOAT) (range 4.0 7.0)) (slot rozlisenie_fotoaparatu (type INTEGER) (range 4 128)) (slot kapacita_baterie (type INTEGER) (range 5 25))) (deftemplate zakaznik (slot znacka (type SYMBOL)) (slot model (type STRING)) (slot rozlisenie (type SYMBOL) (allowed-values HD FULL_HD Q_HD)) (slot SD_Karta (type SYMBOL) (allowed-values ano nie)) (slot interna_pamat (type INTEGER) (range 32 512)) (slot operacny_system (type SYMBOL) (allowed-values iOS android ine)) (slot uhlopriecka (type FLOAT) (range 4.0 7.0)) (slot rozlisenie_fotoaparatu (type INTEGER) (range 4 128)) (slot kapacita_baterie (type INTEGER) (range 5 25))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Vstupy ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (deffacts mobily_na_sklade (mobily(znacka Motorola)(model "Defy")(rozlisenie HD)(SD_Karta ano)(interna_pamat 64)(operacny_system android)(uhlopriecka 6.5)(rozlisenie_fotoaparatu 60)(kapacita_baterie 20)) (mobily(znacka Samsung)(model "Galaxy")(rozlisenie FULL_HD)(SD_Karta ano)(interna_pamat 128)(operacny_system android)(uhlopriecka 6.5)(rozlisenie_fotoaparatu 32)(kapacita_baterie 25)) (mobily(znacka Iphone)(model "14")(rozlisenie FULL_HD)(SD_Karta nie)(interna_pamat 128)(operacny_system iOS)(uhlopriecka 6.1)(rozlisenie_fotoaparatu 12)(kapacita_baterie 25)) (mobily(znacka Iphone)(model "13")(rozlisenie Q_HD)(SD_Karta nie)(interna_pamat 128)(operacny_system iOS)(uhlopriecka 6.1)(rozlisenie_fotoaparatu 12)(kapacita_baterie 20)) (mobily(znacka Asus)(model "Zenfone")(rozlisenie HD)(SD_Karta ano)(interna_pamat 32)(operacny_system android)(uhlopriecka 5.9)(rozlisenie_fotoaparatu 64)(kapacita_baterie 14)) (mobily(znacka Samsung)(model "Galaxy")(rozlisenie Q_HD)(SD_Karta nie)(interna_pamat 128)(operacny_system android)(uhlopriecka 6.1)(rozlisenie_fotoaparatu 12)(kapacita_baterie 25)) (mobily(znacka Motorola)(model "Moto")(rozlisenie FULL_HD)(SD_Karta ano)(interna_pamat 32)(operacny_system android)(uhlopriecka 6.3)(rozlisenie_fotoaparatu 13)(kapacita_baterie 15)) (mobily(znacka Xiaomi)(model "Redmi")(rozlisenie HD)(SD_Karta ano)(interna_pamat 64)(operacny_system android)(uhlopriecka 6.5)(rozlisenie_fotoaparatu 108)(kapacita_baterie 16)) ) (defrule vypis_uvod => (printout t "Vitajte v programe na vyber telefonu" crlf) (printout t "Prosim vyberte vase specifikacie: " crlf)) (defrule osobne_hodnoty => (printout t "Zadajte znacku" crlf) (bind ?znacka (symbol-value (read))) (printout t "Zadajte model" crlf) (bind ?model (read)) (printout t "Zadajte ci vas vybrany telefon podporuje SD Karty (ano/nie)" crlf) (bind ?SD_Karta (symbol-value (read))) (printout t "Zadajte rozlisenie displeja (HD, FULL_HD, Q_HD)" crlf) (bind ?rozlisenie (symbol-value (read))) (printout t "Zadajte velkost internej pamete (32 - 512)" crlf) (bind ?interna_pamat (integer (read))) (printout t "Zadajte uhlopriecku (4.0 - 7.0)" crlf) (bind ?uhlopriecka (float (read))) (printout t "Zadajte operacny system(iOS, android, ine)" crlf) (bind ?operacny_system (symbol-value (read))) (printout t "Zadajte rozlisenie_fotoaparatu (4 - 128)" crlf) (bind ?rozlisenie_fotoaparatu (integer (read))) (printout t "Zadajte kapacitu baterie v hodinach (5 - 25)" crlf) (bind ?kapacita_baterie (integer (read))) (assert (zakaznik (znacka ?znacka) (model ?model) (rozlisenie ?rozlisenie) (SD_Karta ?SD_Karta) (interna_pamat ?interna_pamat) (operacny_system ?operacny_system) (uhlopriecka ?uhlopriecka) (rozlisenie_fotoaparatu ?rozlisenie_fotoaparatu) (kapacita_baterie ?kapacita_baterie)))) (defrule telefon_je_na_sklade ?z <- (zakaznik (znacka ?znacka) (model ?model) (rozlisenie ?rozlisenie) (SD_Karta ?SD_Karta) (interna_pamat ?interna_pamat) (operacny_system ?operacny_system) (uhlopriecka ?uhlopriecka) (rozlisenie_fotoaparatu ?rozlisenie_fotoaparatu) (kapacita_baterie ?kapacita_baterie)) (mobily (znacka ?znacka) (model ?model) (rozlisenie ?rozlisenie) (SD_Karta ?SD_Karta) (interna_pamat ?interna_pamat) (operacny_system ?operacny_system) (uhlopriecka ?uhlopriecka) (rozlisenie_fotoaparatu ?rozlisenie_fotoaparatu) (kapacita_baterie ?kapacita_baterie)) => (retract ?z) (printout t "Telefon je na sklade:" ?znacka ?model crlf) (halt)) (defrule telefon_nie_je_na_sklade ?z <- (zakaznik (znacka ?znacka) (model ?model) (rozlisenie ?rozlisenie) (SD_Karta ?SD_Karta) (interna_pamat ?interna_pamat) (operacny_system ?operacny_system) (uhlopriecka ?uhlopriecka) (rozlisenie_fotoaparatu ?rozlisenie_fotoaparatu) (kapacita_baterie ?kapacita_baterie)) (not (mobily (znacka ?znacka) (model ?model) (rozlisenie ?rozlisenie) (SD_Karta ?SD_Karta) (interna_pamat ?interna_pamat) (operacny_system ?operacny_system) (uhlopriecka ?uhlopriecka) (rozlisenie_fotoaparatu ?rozlisenie_fotoaparatu) (kapacita_baterie ?kapacita_baterie))) => (retract ?z) (printout t "Bohuzial zadany telefon nemame na sklade" crlf) (halt))
关键修改点
- 类型转换:对SYMBOL、INTEGER、FLOAT类型的输入做对应转换,确保
zakaznik事实槽值类型与mobily一致。 - 事实绑定与移除:用
?z <-绑定zakaznik事实,动作中(retract ?z)移除该事实,避免规则重复触发。 - 停止推理:添加
(halt)终止推理过程,确保只执行一次匹配结果。
内容的提问来源于stack exchange,提问作者Filip Štepanovský
相关产品推荐
相关产品推荐

