gpt4 book ai didi

prolog - 通过用户输入将参数保存到事实中

转载 作者:行者123 更新时间:2023-12-02 06:34:28 25 4
gpt4 key购买 nike

几天前,我问了一个关于Prolog中基础输入/输出的问题,但是现在我有另一个问题。

我正在大学里做一个有关ITS诊断的Prolog项目。

假设我从一些基本事实入手:

lesion(herpes).
lesion(sifilis).
ampolla(herpes).
inguinal(herpes).
fiber(herpes).
headache(herpes).
picazon(herpes).
secrecion(sifilis).

我有一些测试的基本规则:
its(herpes):-lesion(herpes), inguinal(herpes), picazon(herpes), fiber(herpes).
its(herpes):- ampolla(herpes), headache(herpes), picazon(herpes).
its(sifilis):-secrecion(sifilis), lesion(sifilis).

我的问题是:

我有什么办法可以通过使用问题而不是自己设置问题来保存每个论点?让我解释:

例如,我想声明一个空事实,例如: lesion(_),然后询问用户: Do you have any lesion?如果答案是肯定的,那么事实将是: lesion(herpes).
之后,我将问另一个问题,直到获得带有论点的所有事实,以便我打印:X =疱疹或类似的东西。

那有可能吗?

任何帮助将不胜感激。

最佳答案

编辑:我已经意识到这并不能回答您提出的问题,而是提出了解决该问题的另一种方法。

您想要实现的目标很容易在Prolog中实现,但是我认为从头开始重做您的方法可能很有意义。

Prolog语法源自first order predicate calculus。因此,形式为p(s)的单个位置谓词的标准读数为“sp”。函子p被视为谓词,它赋予s一些品质或属性。这种方法的一个相当常识的扩展是读取事物之间的关系归因较高的谓词(即,更多的参数),因此可以将r(a,b)读为“a代表rb的关系”。

在这种共同阅读下,您的事实会说“疱疹是一种病变,梅毒是一种病变,疱疹是一种安波拉,等等……”这没有多大意义。更重要的是,您当前的代码没有定义任何关系,因此无法通过统一获得任何有趣的事实。

您的its/1规则表现出类似的异常情况,并且可能是被误导的方法(并不是说异常=误导了)。通常,我们将每个谓词都视为表达基本陈述。如果我想说明苏格拉底是凡人的事实,我就写mortal(socrates),包括主语和谓语。同样,如果我想表达苏格拉底教柏拉图的关系事实,我会写teaches(socrates, plato),包括关系的特征和函子teaches来描述这种关系。我将its(herpes)读为“是疱疹”,但尚不清楚“它”指的是什么,也没有任何有关归因于疱疹的关系或属性(property)的信息。

我将为您的程序建议另一种方法,然后提供一些代码以实现所需的输入/输出接口(interface)。

我认为您的事实意味着要描述疾病的症状。我将使用谓词symptom/2来明确指出这一点,以便symptom(Symptom, Disease)表示“症状是疾病疾病的症状”:

symptom(lesion, herpes).
symptom(lesion, sifilis).
symptom(ampolla, herpes).
symptom(inguinal, herpes).
symptom(fiber, herpes).
symptom(headache, herpes).
symptom(picazon, herpes).
symptom(secrecion,sifilis).

请注意,这组事实已经使我们能够提取有用的信息,而事实却并非如此。例如,我们可以通过使用 Symptom参数的自由变量查询来找出疾病的所有症状:
?- symptom(X, herpes).
X = lesion ;
X = ampolla ;
X = inguinal ;
X = fiber ;
X = headache ;
X = picazon.

或者我们可以通过在 Disease参数中使用自由变量查询来找出特定症状可能指示的疾病:
?- symptom(inguinal, X).
X = herpes.

关于您的规则,我认为他们是在试图说具有某某症状的人可以被诊断出某某疾病。我可以这样写:
%% indicate_disease(+Symptoms:List, ?Disease:Atom)
%
% True if all symptoms in the list Symptoms are symptoms of the disease Disease.
%

indicate_disease(Symptoms, Disease) :-
foreach( member(Symptom, Symptoms), symptom(Symptom, Disease) ).

我读了一条规则,说:“如果对于列表 Symptoms成员的每个 DiseaseSymptom是疾病 Symptoms的症状,则 Symptom列表中的症状表示疾病 Disease”。当我的代码读起来像是一个令人讨厌的乏味,完全多余的语句时,我通常会觉得自己处在正确的轨道上。

当然,如果您只需要特定的症状集就可以表明疾病,则需要使规则变得不太通用。您可以通过多种方式执行此操作。例如,您可以编写谓词 indicate_disease/2以包括特定的症状分类:
indicate_disease(Symptoms, herpes) :-
Symptoms = [lesion, inguinal, picazon, fiber].

或者,您也可以编写一个中间谓词,该谓词描述足以表明诊断的特定症状-疾病关系集:
indications_of(sifilis, [secrecion, lesion]).

然后编写 indicate_disease/2以使用此谓词:
indicate_disease(Symptoms, Disease) :-
indications_of(Disease, Symptoms).

有了这样的代码,我们现在就可以通过以下方式的查询来“诊断”(假装):
?- indicate_disease([lesion, inguinal, picazon, fiber], Disease).
Disease = herpes.

现在您的问题开始发挥作用:如何从用户那里收集症状作为输入?如果仅将终端用于接口(interface),则以下模式就足够了:
inquire_about_symptoms(Symptoms) :-
user_has_symptoms(Symptoms, [], HasSymptoms),
( indicate_disease(HasSymptoms, Disease)
-> format('You have ~w -- :(~n', [Disease])
; writeln('You are disease free! :)')
).

user_has_symptoms([], HasSymptoms, HasSymptoms).
user_has_symptoms([S|Symptoms], AccSymptoms, HasSymptoms) :-
user_has_symptom(S, Answer),
( Answer == yes
-> NewAccSymptoms = [S|AccSymptoms]
;
Answer == no
-> NewAccSymptoms = AccSymptoms
),
user_has_symptoms(Symptoms, NewAccSymptoms, HasSymptoms).

user_has_symptom(Symptom, Answer) :-
format('Do you have any ~w?~nAnswer "yes" or "no": ', [Symptom]),
read(Answer).

用法如下:
?- inquire_about_symptoms([lesion, inguinal, picazon, fiber]).
Do you have any lesion?
Answer "yes" or "no": yes.
Do you have any inguinal?
Answer "yes" or "no": yes.
Do you have any picazon?
Answer "yes" or "no": yes.
Do you have any fiber?
Answer "yes" or "no": yes.
You have herpes -- :(

编辑:已添加以解决评论中的后续问题。

您可以通过从检查某些症状组是否为疾病的规则中分离出哪些症状组指示疾病的事实,来使症状与一组适应症相匹配。然后,您只需要检查用户报告的症状的所有成员是否也是这些症状组之一的成员。例如,如果我们有这样声明的症状集:
indications_of(herpes, [lesion, inguinal, picazon, fiber]).
indications_of(siphilis, [...]).
indications_of(..., ...).
....

然后,以下规则将检查一个列表中的所有成员是否都是另一个列表中的成员,而不仅仅是尝试统一列表:
indicate_disease(UserSymptoms, Disease) :-
indications_of(Disease, DiseaseSymptoms),
forall(member(Symptom, DiseaseSymptoms), member(Symptom, UserSymptoms)).

请注意,这仅在 DiseaseSymptoms中存在每个 UserSymptoms时才起作用。另一种方法可能是使用 sort(List, Sorted)确保所有症状都在排序列表中,然后仅通过统一列表进行测试。

要查找可能由一组症状指示的所有疾病,您可以像这样使用 findall/3 :
indicate_diseases(UserSymptoms, Diseases) :-
findall(Disease,
( indications_of(Disease, DiseaseSymptoms),
forall( member(Symptom, DiseaseSymptoms),
member(Symptom, UserSymptoms) ),
Diseases
).

我们可能会读到说“ UserSymptoms表示 Diseases,如果 DiseasesDisease的所有值的列表,使得 DiseaseSymptomsDisease的指示,并且对于 Symptom列表的所有元素 DiseaseSymptomsSymptom也是列表的元素 UserSymptoms。”

请注意,当使用 findall/3时,否定结果将是一个空列表,而不是 false,因为,例如,
?- findall(X, X \= X, Xs).
Y = [].

因此,返回给用户的报告将必须测试 []而不是失败,并且 inquire_about_symptoms/1中的条件现在看起来更像以下内容:
...
indicate_diseases(HasSymptoms, Diseases)
( Diseases = []
-> writeln('You are disease free! :)~n'
; format('You have ~w -- :(~n', [Diseases])
).

我没有测试过任何添加的代码,但我认为基本思想都很合理。

关于prolog - 通过用户输入将参数保存到事实中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23378414/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com