Prolog检查列表中的第一个元素是否相等,列表中的第二个项目是否相等



我想比较两个列表,第一个元素不应该相等,第二个元素应该相等。

示例数据库:

likes(josh,muse).
likes(sam,muse).
likes(josh,gnr).
likes(sam, radiohead).

所以它应该返回true for same([josh,muse],[sam,muse(。

这就是我迄今为止所尝试的:

same([H1|R1], [H2|R2]):-
H1 = H2,
same(R1,R2).

这对每个组合都返回false。

same/2谓词定义中使用的列表的[Head|Tail]Prolog表示法提供了对列表headtail的访问。列表的尾部本身就是一个(可能是空的(列表。但在您的情况下,您希望访问第一个和第二个元素,这可以通过编写[First, Second| _]来完成(即,通过枚举用逗号分隔的元素;这里我使用匿名变量作为尾部,因为我们不需要它,因此我们可以忽略它(。

您的谓词可以通过重写为:来修复

same([F1,S1|_], [F2,S2|_]):-
F1 == F2,
S1 == S2.

如果您知道参数总是包含两个元素的列表,则可以将谓词简化为:

same([F1,S1], [F2,S2]):-
F1 == F2,
S1 == S2.

示例调用:

?- same([josh,muse], [sam,muse]).
true.
?- same([sam,muse], [sam,muse]).
false.
?- same([josh,muse], [sam,maria]).
false.

最后请注意,您的问题是关于术语平等,但在您的解决方案尝试中,您使用的是名词统一。这些具有不同的语义,不应混淆。

在阅读问题时,您首先给出了一个事实数据库

likes(josh,muse).
likes(sam,muse).
likes(josh,gnr).
likes(sam, radiohead).

但随后使用了谓词的列表

same([josh,muse], [sam,muse]).

正如保罗从列表开始回答的那样,我将从事实开始回答。

第一件事是创建一个谓词,它读取事实,执行一些逻辑并返回结果。

same_1(P1,P2,Item) :-
likes(P1,Item),
likes(P2,Item).

它给出

?- same_1(P1,P2,Item).
P1 = P2, P2 = josh,
Item = muse ;
P1 = josh,
P2 = sam,
Item = muse ;
P1 = sam,
P2 = josh,
Item = muse ;
P1 = P2, P2 = sam,
Item = muse ;
P1 = P2, P2 = josh,
Item = gnr ;
P1 = P2, P2 = sam,
Item = radiohead.

因此,这需要确保P1与P2不相同。

same_2(P1,P2,Item) :-
likes(P1,Item),
likes(P2,Item),
P1 = P2.

它给出

?- same_2(P1,P2,Item).
P1 = josh,
P2 = sam,
Item = muse ;
P1 = sam,
P2 = josh,
Item = muse ;
false.

仍然有两个答案是有效的,但本质上是重复的。要删除这些重复项,需要存储所有结果,以便可以根据现有结果检查每个新结果,而不是将其添加到当前结果中。此外,在存储结果之前,需要对它们进行规范化,以便无论最初创建时名称的排序方式如何,在保存之前进行比较时,它们的顺序都是相同的。

修改代码以创建规范化条目。

same_3(P1,P2,Item) :-
likes(T1,Item),
likes(T2,Item),
T1 = T2,
normalize(T1,T2,P1,P2).
normalize(P1,P2,P1,P2) :- P1 @> P2.
normalize(P1,P2,P2,P1) :- P1 @=< P2.

返回

?- same_3(P1,P2,Item).
P1 = sam,
P2 = josh,
Item = muse ;
P1 = sam,
P2 = josh,
Item = muse ;
false.

请注意,此结果的名称顺序相同。

现在只需在生成结果时保存结果,并只向结果中添加唯一项。这是使用setof/3完成的。

?- setof((P1,P2,Item),(same_3(P1,P2,Item)),Bag).
Bag = [(sam, josh, muse)].

最新更新