我想根据某些用户的答案总结SWI-Prolog

时间:2019-05-14 20:49:54

标签: 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 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).

1 个答案:

答案 0 :(得分:1)

我将向您展示一种基本不同的方法来实施该程序,并更好地利用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('Do you have X?', has_x)时,动态存储将收到risk(has_x, yes)risk(has_x, 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)].

现在,您可以看到Template(第一个参数)只是一些任意结构,其中填充了findall/3通过运行第二个参数Goal找到的变量。因此,如果我们在目标查询中查找惩罚值的列表,我们也可以只获取它们。像这样:

?- findall(Penalty,    %% <- template
           (risk(Factor, yes), risk_penalty(Factor, Penalty)),   %% <- goal
           Penalties). %% <- result
Penalties = [2, 3].

然后我们可以仅添加sumlist/2来添加所有内容:

?- findall(Penalty, 
           (risk(Factor, yes), risk_penalty(Factor, Penalty)), 
           Penalties), 
   sumlist(Responsa, Score).
Responsa = [2, 3],
Score = 5.

现在我们可以完成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.

我希望您能看到令人愉悦的结果,减少程序性,并易于修改和维护。