0

我将如何陈述有关事实的“一般”情况?假设我需要声明“每个人都喜欢喜欢他/她的人”,并且我有一个可能会或可能不喜欢彼此的人的列表。

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

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

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

4

3 回答 3

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/1add_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.

于 2013-10-01T07:15:10.657 回答
0

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

因此,解决方案是:

%% 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来找到所有彼此不喜欢的配对。

于 2013-10-01T07:34:56.963 回答
0

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

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

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

第二个子句是“如果 OtherGirl 喜欢 Girl,Girl 喜欢 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).
于 2013-10-01T12:21:20.850 回答