我想根据某些用户的回答,在SWI Prolog中求和

我想根据某些用户的回答,在SWI Prolog中求和,prolog,Prolog,我需要根据特定的用户答案对变量求和,并且我开始了解Prolog语法和范例 现在,我可以读取用户数据,并将其打印出来,但我缺乏一种累积结果的方法,因为现在的结果不一致 我现在得到的是: inicio :- write('¿You have overweight yes/no?'), read(R1), write('¿Are you a smoker yes/no?'), read(R2), write('¿Do you have some direct r

我需要根据特定的用户答案对变量求和,并且我开始了解Prolog语法和范例

现在,我可以读取用户数据,并将其打印出来,但我缺乏一种累积结果的方法,因为现在的结果不一致

我现在得到的是:

inicio :-
    write('¿You have overweight yes/no?'),
    read(R1),
    write('¿Are you a smoker yes/no?'),
    read(R2),
    write('¿Do you have some direct relative with diabetes?'),
    read(R3),
    Risk is 0,
    ( R1 = yes -> Risk is Risk + 2 ; Risk is Risk + 0 ),
    imprimir(['The result is ', Risk]),
    ( R2 = yes -> Risk is Risk + 1 ; Risk is Risk + 0 ),
    imprimir(['The result is ', Risk]),
    ( R3 = yes -> Risk is Risk + 3 ; Risk is Risk + 0 ),
    imprimir(['The result is ', Risk]).

imprimir([]).
imprimir([Term| Terms]) :-
    write(Term),
    imprimir(Terms).

我将向您展示一种完全不同的方法来处理这个程序,更好地利用Prolog。首先,让我们做一张处罚表。为程序的配置制作表格通常是一件有用的事情:

risk_penalty(overweight, 2).
risk_penalty(smoker,     1).
risk_penalty(diabetes,   3).
现在我们对这个问题有了一个统一的思考方式,让我们看看我们是否能够以统一的方式从用户那里获取信息。让我们使用动态存储来跟踪用户告诉我们的内容,因为它将简化以后的查询:

:- dynamic risk/2.

ask(Prompt, Fact) :-
    format('~a [yes/no]> ', [Prompt]),
    read(Response),
    assertz(risk(Fact, Response)).
现在我们有一个小谓词可以用来访问用户。这种打印读取断言函数在像您这样的小型专家系统中非常常见,因为它可以帮助您将系统的逻辑与其前端分离。当您执行
ask('youhavex?',hasex)
时,动态存储将接收
风险(hasex,yes)
风险(hasex,no)
,具体取决于用户输入的内容。它还为您提供了一个自然的场所,通过检查用户输入并重新询问您是否得到了一些奇怪的信息,可以使用户输入更加健壮

现在,我们可以更清晰地执行初始循环:

inicio :-
    ask('Are you overweight?', overweight),
    ask('Are you a smoker?', smoker),
    ask('Do you have some direct relative with diabetes?', diabetes).
这只是面试部分。现在,如果您运行一次,回答“是”、“否”、“是”,那么数据库将包含以下事实:

?- risk(Factor, Response).
Factor = overweight,
Response = yes ;
Factor = smoker,
Response = no ;
Factor = diabetes,
Response = yes.
我们现在需要做的是选择“是”的因素,然后查找它们的惩罚并将其相加。为此,我们可以使用
findall/3
,它获取一个模板、一个目标并返回一个结果列表:

?- findall(risk(Factor, Response), risk(Factor, Response), Responses).
Responses = [risk(overweight, yes), risk(smoker, no), risk(diabetes, yes)].
正如你所看到的,我在这里使用了相同的模板和目标,只是为了查看所有结果,但我们可以在其中输入“是”来过滤我们关心的风险因素:

?- findall(risk(Factor), risk(Factor, yes), Responses).
Responses = [risk(overweight), risk(diabetes)].
现在您可以看到模板(第一个参数)只是一个任意结构,其中填充了通过运行第二个参数
Goal
找到的变量
findall/3
。因此,如果我们在目标查询中查找惩罚值,我们也可以获得惩罚值列表。像这样:

?- findall(Penalty,    %% <- template
           (risk(Factor, yes), risk_penalty(Factor, Penalty)),   %% <- goal
           Penalties). %% <- result
Penalties = [2, 3].
现在我们可以完成
inicio/0
谓词:

inicio :-
    retractall(risk(_, _)),
    ask('Are you overweight?', overweight),
    ask('Are you a smoker?', smoker),
    ask('Do you have some direct relative with diabetes?', diabetes)
    findall(Penalty,
            (risk(Factor, yes), risk_penalty(Factor, Penalty)), Penalties),
    sumlist(Penalties, Score),
    format('The result is ~a~n', [Score]).
运行时,现在看起来如下所示:

?- inicio.
Are you overweight? [yes/no]> yes.
Are you a smoker? [yes/no]> |: no.
Do you have some direct relative with diabetes? [yes/no]> |: yes.
The result is 5
true.

我希望您能发现结果令人满意,程序性更少,更易于修改和维护。

您不能在Prolog中修改变量,每个
风险都是风险+…
都会失败。您每次都需要引入新变量,或者找到一种不创建大量中间状态的方法来实现这一点。我还需要一些帮助,我在Swi Prolog 7.6中遇到了这个错误,更新为8.02,但仍然是一样的:
error:格式化序列的非法参数~s:6 error:in:error:[9]format('结果是~s~n',[6])错误:[7]错误:错误:注意:由于上次调用优化,某些帧丢失。错误:在调试模式下重新运行程序(:-debug。)以获取更多详细信息。
Sry,问题已经解决,现在我使用简单的“write”s,现在我需要一种方法将每次执行的分数重新启动为零。@Alcides我想我在自己的代码中将其更改为~a,我将更新答案。要重新开始评分,只需在
inicio/0
开始时
retractall(risk(,))
。就这样做了,伙计,你是我的救世主,只要一件事,我就完成了:如果我想对答案进行分类,让我们假设分数在0和3之间为“低”,在4和5之间为“中”,在6和更高之间为“高”。@Alcides尝试类似的方法:
category(分数,低):-介于(1,3,分数)之间。
?- inicio.
Are you overweight? [yes/no]> yes.
Are you a smoker? [yes/no]> |: no.
Do you have some direct relative with diabetes? [yes/no]> |: yes.
The result is 5
true.