我想比较2个列表,第一个元素不应该相等,第二个元素应该相等。
示例数据库:
likes(josh,muse).
likes(sam,muse).
likes(josh,gnr).
likes(sam, radiohead).
因此对于相同的内容([josh,muse],[sam,muse]),它应该返回true。
这是我到目前为止尝试过的:
same([H1|R1], [H2|R2]):-
H1 \= H2,
same(R1,R2).
每个组合都返回false。
答案 0 :(得分:1)
您在[Head|Tail]
谓词的定义中使用的列表的same/2
序言符号可访问列表 head 和 tail 。列表的尾部本身就是一个(可能为空)列表。但是在您的情况下,您想访问第一个和第二个元素,您可以通过编写[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.
最后一点,您的问题是关于术语相等性的,但是在解决方案尝试中,您正在使用术语统一性。它们具有不同的语义,不应混淆。
答案 1 :(得分:1)
在阅读您的问题时,您首先提供了一个事实数据库
likes(josh,muse).
likes(sam,muse).
likes(josh,gnr).
likes(sam, radiohead).
但随后将列表用作谓词
same([josh,muse], [sam,muse]).
Paulo从清单开始回答,我将从事实开始回答。
第一件事是创建一个谓词,以读取事实,执行一些逻辑并返回结果。
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)].