我如何“概括地”陈述事实?假设我需要说“每个人都喜欢喜欢他/她的人”,并且我列出了可能会或可能不喜欢彼此的人。
这是我到目前为止所尝试的,但肯定不是这样做的方法:
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
不幸的是,我不明白警告说的是什么。希望它能让我的意图更清晰。即通过陈述一个事实,我也想说明其他相关事实。
答案 0 :(得分:1)
如果您想动态更改知识库,可以使用assert
s。如果要修改现有谓词,则应将其定义为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会这样理由:
这还不足以使它成为一个正确的程序。因为我们在Prolog你可以说:“给我另一个解决方案”(通常在提示中输入“;”)。 Prolog会认为“我只使用了第一个条款,我没有尝试过第二个条款”。
但这是我们的初步查询。如果您要求所有解决方案,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).