饮食营养专家系统CLIPS代码无结果输出问题求助
饮食营养专家系统CLIPS代码修正方案
问题分析
原代码无法输出结果的核心问题如下:
- 输入规则触发混乱:多个输入规则(read-age、read-height等)触发条件相同,导致同时执行,输入顺序失控,甚至重复输入。
- 事实名称不匹配:计算规则断言的事实(如
daily-calories)与输出规则匹配的事实(如calories-needed)名称不一致,输出规则无法触发。 - 身体状态值大小写不统一:计算规则断言的是
"Underweight"(首字母大写),但输出规则匹配的是underweight(全小写),导致规则不匹配。 - 缺少纤维计算逻辑:系统承诺输出每日纤维需求,但未实现对应计算规则。
- BMI计算公式错误:未将厘米单位的身高转换为米,导致BMI计算值严重偏离实际。
- 输出规则触发条件缺失:输出规则没有等待所有计算完成的逻辑,部分规则因依赖事实未完全生成而无法触发。
修正后的完整代码
(defrule read-gender (initial-fact) => (printout t crlf crlf "欢迎使用饮食营养专家系统" crlf) (printout t "******************************************" crlf) (printout t "本系统将为您生成以下结果:" crlf) (printout t "1. 您的BMI指数及身体状态" crlf) (printout t "2. 基于身体状态的每日推荐卡路里摄入量" crlf) (printout t "3. 基于体重的每日蛋白质需求量" crlf) (printout t "4. 基于年龄的每日钙需求量" crlf) (printout t "5. 基于卡路里需求的每日纤维需求量" crlf) (printout t "6. 基于体重的每日碳水化合物需求量" crlf) (printout t "******************************************" crlf crlf) (printout t "请输入您的性别(Female/Male,区分大小写):") (assert (gender (read)))) (defrule read-age (gender ?) (not (age ?)) => (printout t "请输入您的年龄:") (assert (age (read)))) (defrule read-height (age ?) (not (height ?)) => (printout t "请输入您的身高(单位:厘米):") (assert (height (read)))) (defrule read-weight (height ?) (not (weight ?)) => (printout t "请输入您的体重(单位:千克):") (assert (weight (read)))) (defrule read-activity-days (weight ?) (not (activity-days ?)) => (printout t "请输入您每周锻炼的天数:") (assert (activity-days (read)))) (defrule set-activity-rate-sedentary (activity-days ?days) (test (< ?days 2)) => (assert (activity-rate "Sedentary")) (assert (activity-factor 1.2))) (defrule set-activity-rate-moderate (activity-days ?days) (test (and (>= ?days 2) (< ?days 5))) => (assert (activity-rate "Moderate")) (assert (activity-factor 1.55))) (defrule set-activity-rate-hard (activity-days ?days) (test (>= ?days 5)) => (assert (activity-rate "Hard")) (assert (activity-factor 1.75))) (defrule calculate-bmi (weight ?weight) (height ?height) => (bind ?height-m (/ ?height 100)) ; 将厘米转换为米 (bind ?bmi (/ ?weight (* ?height-m ?height-m))) (assert (bmi ?bmi))) (defrule set-body-status-underweight (bmi ?bmi) (test (< ?bmi 18.5)) => (assert (body-status "underweight"))) ; 统一为小写 (defrule set-body-status-normal-weight (bmi ?bmi) (test (and (>= ?bmi 18.5) (< ?bmi 24.9))) => (assert (body-status "normal-weight"))) ; 统一为小写 (defrule set-body-status-overweight (bmi ?bmi) (test (and (>= ?bmi 24.9) (< ?bmi 29.9))) => (assert (body-status "overweight"))) ; 统一为小写 (defrule set-body-status-obesity (bmi ?bmi) (test (>= ?bmi 29.9)) => (assert (body-status "obesity"))) ; 新增肥胖状态规则 (defrule calculate-daily-calories-female (gender "Female") (activity-factor ?activity-factor) (weight ?weight) (age ?age) (height ?height) => (bind ?height-m (/ ?height 100)) (bind ?bmr (+ 655.1 (+ (* 9.563 ?weight) (* 1.85 ?height-m) (* -4.676 ?age)))) ; BMR公式修正:年龄项为负 (bind ?daily-calories (* ?bmr ?activity-factor)) (assert (calories-needed ?daily-calories)) ; 统一事实名称 (assert (daily-calories ?daily-calories))) (defrule calculate-daily-calories-male (gender "Male") (activity-factor ?activity-factor) (weight ?weight) (age ?age) (height ?height) => (bind ?height-m (/ ?height 100)) (bind ?bmr (+ 66.5 (+ (* 13.75 ?weight) (* 5.003 ?height-m) (* -6.755 ?age)))) ; BMR公式修正:年龄项为负 (bind ?daily-calories (* ?bmr ?activity-factor)) (assert (calories-needed ?daily-calories)) ; 统一事实名称 (assert (daily-calories ?daily-calories))) (defrule set-daily-calcium-baby (age ?age) (test (< ?age 4)) => (assert (calcium-needed "210-270mg")) ; 统一事实名称 (assert (daily-calcium "210-270mg"))) (defrule set-daily-calcium-child (age ?age) (test (and (>= ?age 4) (< ?age 9))) => (assert (calcium-needed "350-450mg")) ; 统一事实名称 (assert (daily-calcium "350-450mg"))) (defrule set-daily-calcium-teen (age ?age) (test (and (>= ?age 9) (< ?age 19))) => (assert (calcium-needed "800mg")) ; 统一事实名称 (assert (daily-calcium "800mg"))) (defrule set-daily-calcium-adult (age ?age) (test (and (>= ?age 19) (< ?age 51))) => (assert (calcium-needed "1000mg")) ; 统一事实名称 (assert (daily-calcium "1000mg"))) (defrule set-daily-calcium-old (age ?age) (test (>= ?age 51)) => (assert (calcium-needed "1200mg")) ; 统一事实名称 (assert (daily-calcium "1200mg"))) (defrule calculate-daily-protein-sedentary (weight ?weight) (activity-rate "Sedentary") => (bind ?daily-protein (* ?weight 0.8)) (assert (protein-needed ?daily-protein)) ; 统一事实名称 (assert (daily-protein ?daily-protein))) (defrule calculate-daily-protein-moderate (weight ?weight) (activity-rate "Moderate") => (bind ?daily-protein (* ?weight 1)) (assert (protein-needed ?daily-protein)) ; 统一事实名称 (assert (daily-protein ?daily-protein))) (defrule calculate-daily-protein-hard (weight ?weight) (activity-rate "Hard") => (bind ?daily-protein (* ?weight 1.2)) (assert (protein-needed ?daily-protein)) ; 统一事实名称 (assert (daily-protein ?daily-protein))) (defrule calculate-daily-carbohydrates (weight ?weight) => (bind ?daily-carbohydrates (* ?weight 2.5)) (assert (carbohydrate-needed ?daily-carbohydrates)) ; 统一事实名称 (assert (daily-carbohydrates ?daily-carbohydrates))) (defrule calculate-daily-fiber (calories-needed ?calories) => (bind ?fiber (round (/ ?calories 100))) ; 每100卡路里对应1克纤维 (assert (fiber-needed ?fiber)) ; 新增纤维计算规则 (assert (daily-fiber ?fiber))) (defrule print-all-results (bmi ?bm) (body-status ?b) (calories-needed ?c) (protein-needed ?p) (calcium-needed ?ca) (fiber-needed ?f) (carbohydrate-needed ?carbo) => (printout t crlf crlf " ######## 计算结果 ######## " crlf) (printout t "1. 您的BMI指数为:" ?bm ",身体状态:" ?b crlf) (printout t "2. 每日推荐卡路里摄入量:" ?c "千卡" crlf) (printout t "3. 每日蛋白质需求量:" ?p "克" crlf) (printout t "4. 每日钙需求量:" ?ca crlf) (printout t "5. 每日纤维需求量:" ?f "克" crlf) (printout t "6. 每日碳水化合物需求量:" ?carbo "克" crlf) ; 根据身体状态输出额外建议 (if (eq ?b "underweight") then (printout t crlf "专家建议:您可每日额外摄入300卡路里(总计" (+ ?c 300) "千卡),每周可增重约0.25千克。" crlf) else (if (eq ?b "normal-weight") then (printout t crlf "专家建议:保持当前卡路里摄入,维持健康体重。" crlf) else (if (eq ?b "overweight") then (printout t crlf "专家建议:每日减少300卡路里摄入(总计" (- ?c 300) "千卡),逐步控制体重。" crlf) else (printout t crlf "专家建议:每日减少500卡路里摄入(总计" (- ?c 500) "千卡),每周可减重约0.5千克。" crlf)))))
关键修正点说明
- 输入规则顺序化:修改输入规则的触发条件,确保只有前一个输入完成后才触发下一个(如
read-age需(not (age ?))),避免输入混乱。 - 统一事实名称:将计算规则断言的事实名称与输出规则匹配的名称统一(如
daily-calories改为calories-needed,同时保留原事实兼容其他规则)。 - 统一身体状态值大小写:将身体状态的断言值改为全小写,与输出规则的匹配条件一致。
- 修正BMI计算逻辑:加入身高单位转换(厘米转米),确保BMI计算结果正确。
- 修正BMR公式:原公式中年龄项符号错误(应为减法),修正后保证卡路里计算准确。
- 新增纤维计算规则:根据每日卡路里需求计算纤维摄入量(每100卡路里对应1克纤维)。
- 统一输出规则:新增
print-all-results规则,等待所有必要事实生成后一次性输出结果,避免分散输出的问题,并加入不同身体状态的建议。
内容的提问来源于stack exchange,提问作者Zeek G
相关产品推荐
相关产品推荐

