我在做一个Prolog程序,它可以找到一组列表的一个子集。这个子集必须符合一些特定的条件,其中一个方面是子集的列表不能相同。什么是困惑我的是,当我试图找到变量匹配,X,如果我把它们插入到查询到位X的例如生成返回错误结果:为什么Prolog会将变量与直接插入的结果匹配失败?
?- containsSet(2, [[3],[7],[7]], X).
X = [[3], [7]] ;
X = [[3], [7]] ;
X = [[7], [7]] ;
false.
?- containsSet(2, [[3],[7],[7]], [[7],[7]]).
false.
怎么可能呢如果在直接插入时返回false,可能会将X与[[7],[7]]匹配。
containsSet的思想是找到在匹配位置中没有匹配元素的长度为N的子集(在本例中为2)(即,子集中没有两个列表具有相同的第一个元素,或者相同第二元素等)。在上面的例子中,[7]和[7]中的第一个(也是唯一)元素匹配,所以它返回false。
非常好的观察!这显然违反了连接的交换性,因此违背了我们对纯逻辑关系的期望。很可能,您在代码中使用非单调和不纯的结构,如'(\ +)/ 1','!/ 0'或if-then-else。你应该使用'dif/2'这样的限制来消除这些杂质,以表示这两个术语是不同的。这会让你的程序变得纯粹,并且可以在更多方向上使用。参见[tag:prolog-dif]和[tag:logical-purity]。另外,'please_use_more_readable_names''insteadOfNamesNoOneCanReadProperly'。 – mat
啊!我在set_is_compatible(SET)行中使用'(\ +)/ 1'几次: - \ +(select(X,SET,R),\ + list_compatible_with_set(X,R))''。我会试着弄清楚如何重写这个。谢谢! – vestlen
是的,我强烈推荐使用'dif/2'这样的纯谓词来代替。 '(\ +)/ 1'版本将为您创建无尽的声明性问题。考虑如下:'?\ \ + select(X,[a,b,c],Rest),X = d.',产生'false',**但**,如果我们只交换这两个目标合意!)交合的交换性,我们得到:'X = d'。如果它的论证是基础的,那么“(\ +)/ 1”是合理的,但是总的来说,你不能依赖这种非单调谓词来获得真正的一般的和陈述性的解决方案。您最好留在Prolog的纯粹和单调子集中以保留这些好的属性。 – mat