如何避免Prolog中兄弟谓词查询出现重复匹配结果?
解决Prolog兄弟关系查询的重复结果问题
你遇到的重复是因为兄弟关系是对称的——如果X是Y的兄弟,Y自然也是X的兄弟,Prolog会遍历所有满足条件的组合,返回这两种情况。下面给你两种简单的解决方法:
方法1:在谓词中添加顺序约束
直接修改sib/2谓词,通过项式顺序比较(@<)固定X和Y的顺序,避免对称重复:
sib(X, Y) :- parent(Z, X), parent(Z, Y), X @< Y.
现在执行sib(X, Y).只会返回一组结果:
X = john, Y = jim ; false.
@<是Prolog的项式比较运算符,会按原子的字典序比较(比如john的字典序比jim小),这样就只会保留X在Y前面的那组结果。
方法2:使用setof/3谓词去重
setof/3的作用是收集所有满足目标的结果,自动去重并排序。它的基本格式是:
setof(结果模式, 目标条件, 结果集合)
针对你的场景,可以通过以下方式使用:
直接查询去重
执行以下查询,会得到去重后的有序结果列表:
?- setof((X,Y), sib(X,Y), Siblings).
返回结果:
Siblings = [(john,jim), (jim,john)].
如果想直接遍历去重后的结果,可结合member/2:
?- setof((X,Y), sib(X,Y), Siblings), member((X,Y), Siblings).
包装成无重复的谓词
如果想让查询直接返回无序的唯一兄弟对,可在setof的目标里加入顺序约束,包装成新谓词:
unique_sib(X, Y) :- setof((X,Y), (parent(Z,X), parent(Z,Y), X @< Y), Siblings), member((X,Y), Siblings).
执行unique_sib(X,Y).只会返回X = john, Y = jim这一组结果。
补充:setof/3基础说明
setof/3会把所有满足「目标条件」的「结果模式」收集成有序且无重复的列表。和它类似的还有bagof/3(不排序、保留重复)和findall/3(不排序、不处理自由变量),但setof是最适合去重场景的工具。
内容的提问来源于stack exchange,提问作者Avrohom Yisroel
相关产品推荐
相关产品推荐

