我正在制作专家系统来诊断病人。我很难问所有的问题,症状,然后给出结果的疾病。谢谢你的帮助。
这是规矩。
疟疾的症状=发烧,颤抖,出汗,头痛。 斑疹伤寒症状=发热、恶心、气胀、abdominal_pain_intemittent、heart_burn、smelling_fart_or_stool。 阑尾炎症状=发热,恶心,abdominal_pain_intemittent,pain_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(_,_,_)).发布于 2015-12-01 07:02:50
在使用trace/0询问所有十个问题之前,您可以很容易地理解为什么您会得到诊断。我建议您尝试一下,因为它对调试Prolog程序非常有帮助。
解决问题的关键是思考反向链接是如何工作的,也就是说,Prolog如何回答查询。Prolog希望回答"true“,但要做到这一点,它必须找到满足查询的变量绑定。当你问它“去”的时候,你首先要问的是diagnosis(X)。因此,要证明"go“是真的,必须找到满足diagnosis(X)的diagnosis(X)。要证明这一点,它必须从那里进入diagnosis/1.,您有一个乏味的retractall, fail目标,这个目标将首先被输入,并且(最终)总是失败。从那里进入diagnosis(malaria),这取决于发烧、颤抖、出汗和头痛的四种症状。这就是为什么Prolog会提示您出现这四种症状。如果你对所有四个人都说“是”,diagnosis(malaria)就成功了!然后回到go,X = malaria和它将继续打印出诊断。
对我来说,这个程序是一个很好的例子,一个非常古老的方法编写Prolog。你有很多声明性的东西和你的I/O混合在一起,你使用事实数据库作为读/写存储,你用失败来驱动某些副作用。我倾向于把责任归咎于教授或教科书,但无论是哪种方式,都很难改进这个程序,也很难理解Prolog的这种风格。
要解决这个问题,最简单的方法是有一个单独的过程,在使用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).同时删除diagnosis(_) :- retractall, fail的第一个子句,否则您的情况不会比以前好。
这仍然相当恶心,但它可能会让你渡过难关。
从长远来看,一般来说,你可能希望专家系统能像面试那样以互动的方式进行面试。毕竟,询问某人是否感到心痛是没有意义的,除非他们感到气胀,有资格进行斑疹伤寒诊断;烧心的症状与其他两种诊断(疟疾或usus buntu)没有关系,只有Prolog才能找到这种依赖关系。但是,这并不意味着Prolog必须在诊断阶段输出任何东西;您可以通过将访谈/数据收集阶段与结果输出阶段分开,只需收集所有的诊断并输出它们,就可以得到两个世界的最佳结果。其结果将是:
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(_,_,_))替换为retractall :- retractall(known(_,_,_))。:)
我还建议您更小心地格式化代码!如果不重新格式化,这是很难理解的。密码卫生问题!
https://stackoverflow.com/questions/34012727
复制相似问题