使用未绑定变量说明事实

时间:2013-10-01 06:23:51

标签: prolog

我如何“概括地”陈述事实?假设我需要说“每个人都喜欢喜欢他/她的人”,并且我列出了可能会或可能不喜欢彼此的人。

这是我到目前为止所尝试的,但肯定不是这样做的方法:

likes(dana, cody).
hates(bess, dana).
hates(cody, abby).

likes(first(Girl, OtherGirl), first(OtherGirl, Girl)).
hates(Girl, OtherGirl):- \+ likes(Girl, OtherGirl).

因为这甚至不会编译。


everybody([dana, cody, bess, abby]).

likes_reflexive(dana, cody).
hates(bess, dana).
hates(cody, abby).
likes_reflexive(X, Y):- likes(X, Y), likes(Y, X).

hates(Girl, OtherGirl):- \+ likes(Girl, OtherGirl).

%% likes_reflikes_reflexive(X, Y):- likes(X, Y), likes(Y, X).
%% user:6: warning: discontiguous predicate likes_reflexive/2 - clause ignored

%% hates(Girhates(Girl, OtherGirl):- \+ likes(Girl, OtherGirl).
%% user:8: warning: discontiguous predicate hates/2 - clause ignored

不幸的是,我不明白警告说的是什么。希望它能让我的意图更清晰。即通过陈述一个事实,我也想说明其他相关事实。

3 个答案:

答案 0 :(得分:1)

如果您想动态更改知识库,可以使用asserts。如果要修改现有谓词,则应将其定义为dynamic,例如:- dynamic(likes/2).。如果谓词未定义,则可以省略它。

add_mutual_likes(X, Y) :- asserta(likes(X, Y)), asserta(likes(Y, X)).

:- initialization(add_mutual_likes(dana, cody)).
加载文件时,

initialization/1调用add_mutual_likes(data, cody)目标。 add_mutual_likes/2将两个事实添加到数据库中。 asserta/1将其参数转换为子句并将其添加到数据库中。

| ?- [my].
yes
| ?- listing(likes/2).
% file: user_input

likes(cody, dana).
likes(dana, cody).

yes
| ?- likes(cody, dana).
yes
| ?- likes(dana, cody).
yes

| ?- add_mutual_likes(oleg, semen).
yes
| ?- listing(likes/2).
% file: user_input

likes(semen, oleg).
likes(oleg, semen).
likes(cody, data).
likes(data, cody).

yes

我使用gprolog

答案 1 :(得分:0)

你想要的是Prolog不关心论证顺序的事实。唉,这样的事情不存在。您可以做的是定义事实,其中隐含含义是对所有参数订单都有效(在下面的示例中为like_each)。但是,当然,你不能以这种方式使用这些事实。相反,您可以定义实际谓词(因此或;)所有可能的参数顺序。

因此,解决方案是:

%% bi-directional like
like_each(dana, cody).

likes(A, B) :- like_each(A, B); like_each(B, A).

%% optional: one-directional like
% likes(cody, sarah).

另外,请注意

hates(Girl, OtherGirl):- \+ likes(Girl, OtherGirl).

如果两个变量都未绑定(例如?- hates(A,B)),它将始终失败。发生这种情况是因为Prolog首先尝试找到likes的匹配项,这对于两个变量总是成功,然后否定结果。因此,您无法使用hates查找彼此不喜欢的所有对。

答案 2 :(得分:0)

让我们从警告开始。它们仅仅是“风格”的建议。他们告诉你,喜欢和讨厌的所有定义应该在一起。相信我,如果你有一个很大的Prolog程序,那么绕过游览代码来获得谓词的完整定义就变成了一场噩梦。这就像在C ++中编写一半函数并在另一个文件中完成它。

现在,你想说“每个人都喜欢喜欢他/她的人”。我不确定你为什么在代码中使用“第一”功能。这就足够了:

likes(dana, cody).
likes(Girl, OtherGirl) :- likes(OtherGirl, Girl).

第二个条款是“女孩喜欢OtherGirl如果OtherGirl喜欢女孩。这不会起作用。 如果你问你的节目“cody喜欢dana是真的吗”

? likes(cody, dana)

Prolog会这样理由:

  • 如果dana喜欢cody(使用第二句),答案是肯定的。
  • 是!因为dana喜欢cody(使用第一个条款)。

这还不足以使它成为一个正确的程序。因为我们在Prolog你可以说:“给我另一个解决方案”(通常在提示中输入“;”)。 Prolog会认为“我只使用了第一个条款,我没有尝试过第二个条款”。

  • 如果dana喜欢cody(使用第二句),答案是肯定的。
  • 根据第二条,答案是肯定的,如果cody喜欢dana。

但这是我们的初步查询。如果您要求所有解决方案,Prolog将一次又一次地给您相同的答案,永远循环。

你可以在这做两件事。第一个是告诉Prolog一个解决方案就足够了。你这样做添加一个“!” (基本上说,清除所有开放的分支以便探索)。

likes(dana, cody) :- !.
likes(Girl, OtherGirl) :- likes(OtherGirl, Girl).

另一种选择是“对计划进行分层”。

direct_likes(dana, cody).
likes(Girl, OtherGirl) :- direct_likes(OtherGirl, Girl), !.
likes(Girl, OtherGirl) :- direct_likes(Girl, OtherGirl).