我正在建立专家系统来诊断患者。而且我很难提出症状的所有问题,然后给出疾病的结果。谢谢你的帮助。
这是规则。
疟疾症状=发烧,发抖,出汗,头痛。
斑疹伤寒的症状=发烧,恶心,胃肠胀气,腹部疼痛,心脏灼热,嗅觉嗅觉,肛门疼痛。
阑尾炎的症状=发烧,恶心,腹部疼痛,疼痛_in_lower_right_abdominal。
我必须向用户询问所有这10个问题的症状,并阅读答案。 例如:
发烧? :是的。 发抖? :是的。 出汗? :没有。 头痛? :没有。 恶心? :是的。 胀气? :是的。abdominal_pain_intemittent? :是的。
heart_burn? :没有。
smelling_fart_or_stool? :没有。
pain_in_lower_right_abdominal? :没有。
程序提问后,程序应该给出这样的疾病结果
诊断:疟疾,斑疹伤寒,阑尾炎。
诊断是疟疾,斑疹伤寒,阑尾炎=>因为疟疾有2种症状,4种斑疹伤寒症状,3种阑尾炎症状。
我的代码问题是程序在显示所有问题之前给出诊断结果。
这是编码
go :- diagnosis(X),
write('diagnosis are : '),nl,
write(X),nl,fail.
diagnosis(_) :- retractall, fail.
diagnosis(malaria) :- fever(yes), shivering(yes), sweating(yes), headache(yes).
diagnosis(tipes) :- fever(yes), nausea(yes), flatulence(yes), abdominal_pain_intemittent(yes), heart_burn(yes), smelling_fart_or_stool(yes).
diagnosis('usus buntu') :- fever(yes), nausea(yes),abdominal_pain_intemittent(yes), ain_in_lower_right_abdominal(yes).
fever(X) :- ask(fever,X).
shivering(X) :- ask(shivering,X).
sweating(X) :- ask(sweating,X).
headache(X) :- ask(headache,X).
nausea(X) :- ask(nausea,X).
flatulence(X) :- ask(flatulence,X).
abdominal_pain_intemittent(X) :- ask('abdominal_pain_intemittent',X).
heart_burn(X) :- ask('heart_burn',X).
smelling_fart_or_stool(X) :- ask('smelling_fart_or stool',X).
pain_in_lower_right_abdominal(X) :- ask('pain_in_lower_right_abdominal',X).
known(yes, a, b).
ask(A, V):- known(yes, A, V), !.
ask(A, V):- known(_, A, V), !, fail.
ask(A, _):- known(yes, A, _), !, fail.
ask(A, V):- write(A:V), write('? : '), read(Y), asserta(known(Y, A, V)), Y == yes.
retractall :- retract(known(_,_,_)).
答案 0 :(得分:2)
在使用trace/0
询问所有十个问题之前,您可以轻松了解诊断原因。我建议您尝试一下,因为它对调试Prolog程序非常有帮助。
未知的关键是考虑反向链接的工作方式,即Prolog如何回答查询。 Prolog希望得到答案" true"但要做到这一点,它必须找到满足查询的变量绑定。当你问它"去,"你要问的第一件事就是diagnosis(X)
。所以要证明"去"是的,它必须找到满足X
的{{1}}。为了证明这一点,它必须输入diagnosis(X)
从那里,你有一个无味的diagnosis/1.
目标,它将首先被输入并且(最终)总是会失败。从那里你进入retractall, fail
,这取决于发烧,发抖,出汗和头痛的四个症状。所以这就是Prolog提示你出现这四种症状的原因。假设你说"是"对所有四个人来说,diagnosis(malaria)
成功了!然后回到go diagnosis(malaria)
,它将继续打印诊断。
对我来说,这个程序是一个非常老派的Prolog编写方法的好例子。你有很多与你的I / O混合的声明性东西,你使用事实数据库作为读/写存储,并且你使用失败以程序方式驱动某些副作用。我倾向于把责任推到教授或教科书的脚下,但不管怎样,要改进这个项目或用这种风格理解Prolog将是非常困难的。
解决问题最简单的方法是在接触X = malaria
之前有一个单独的过程来收集症状。这些变化看起来像这样:
diagnosis/1
同时删除go :-
retractall,
ask_everything,
diagnosis(X),
write('diagnosis are : '),nl,
write(X),nl,fail.
ask_everything :-
fever(yes), shivering(yes), sweating(yes), headache(yes),
nausea(yes), flatulence(yes), abdominal_pain_intemittent(yes),
heart_burn(yes), smelling_fart_or_stool(yes),
pain_in_lower_right_abdominal(yes).
的第一个条款,或者你将不会比以前更好。
这仍然相当严重,但它可能会让你超越驼峰。
长期而言,一般来说,您可能希望专家系统以交互方式执行面试。毕竟,除非他们感到肠胃胀气并且有资格进行斑疹伤寒诊断,否则没有必要问某人是否感到胃灼热;胃灼热的症状与其他两种诊断(疟疾或usus buntu)无关,并且找出这种依赖关系只是Prolog可以做的事情。这并不意味着Prolog必须在诊断阶段输出任何东西;通过收集所有诊断然后输出它们,您可以通过将访谈/数据收集阶段与结果输出阶段分开来获得两全其美。结果如下:
diagnosis(_) :- retractall, fail
运行它看起来像这样:
go :-
retractall,
findall(X, diagnosis(X), Diagnoses),
writeln('diagnoses are: '),
display_diagnoses(Diagnoses).
display_diagnoses([]).
display_diagnoses([X|Rest]) :-
write(' '), write(X), nl,
display_diagnoses(Rest).
这让我感到非常明显,没有实质性的代码更改。希望这有帮助!
哦,还有一件事:用?- go.
fever:yes? : yes.
shivering:yes? : |: yes.
sweating:yes? : |: yes.
headache:yes? : |: yes.
nausea:yes? : |: no.
diagnoses are:
malaria
true.
?-
替换retractall :- retract(known(_,_,_))
。 :)
我还建议您更仔细地格式化代码!没有重新格式化它就很难理解。代码卫生很重要!