我正在制作一个Prolog程序,该程序查找一组列表的子集。该子集必须匹配某些特定条件,一方面是该子集的列表不能相同。令我感到困惑的是,当我尝试找到变量X的匹配项时,如果我将它们插入查询中以代替X,它会生成返回false的结果。例如:

?- containsSet(2, [[3],[7],[7]], X).
X = [[3], [7]] ;
X = [[3], [7]] ;
X = [[7], [7]] ;
false.

?- containsSet(2, [[3],[7],[7]], [[7],[7]]).
false.


如果直接插入X时返回false,如何将X与[[7],[7]]匹配?

containsSet的想法是找到一个长度为N(在本例中为2)的列表子集,该子集在匹配位置没有匹配元素(即子集中的两个列表都没有相同的第一元素或相同的第二元素,等等) 。在上面的示例中,[7]和[7]的第一个(也是唯一一个)元素匹配,因此它返回false。

最佳答案

首先,恭喜我初学者在问题中看到的最具说明性和正当性的观察之一!

一方面,逻辑上的合取是最基本和最著名的属性之一。另一方面,许多Prolog初学者未能意识到使用像(\+)/1这样的非单调谓词几乎总是会破坏这些基本不变式。您注意到这里发生了非常出乎意料的事情,并且您期望Prolog采取更正确的行为是正确的。幸运的是,针对此类问题的声明式解决方案现在在Prolog系统中得到了前所未有的广泛传播。

首先,考虑一下如果在程序中使用(\+)/1会很快出现的一些问题:

?- X = d, \+ member(X, [a,b,c]).
X = d.

yet, if we simply exchange the goals by commutativity of conjunction, we get the different answer:

?-  \+ member(X, [a,b,c]), X = d.
false.

This shows that (\+)/1 is not monotonic: It can cause a more general query to fail although a more specific query yields solutions:

?-  \+ member(X, [a,b,c]).
false.

?- \+ member(d, [a,b,c]).
true.

Thus, non-monotonic predicates cause all kinds of impurities and violate declarative semantics. Declaratively, knowing that there are solutions, we certainly expect the more general query to succeed, but it fails.

In this concrete, to specify that a term is different from all other terms in a list, use the constraint dif/2. dif/2 works in all directions, and yields correct answers also if its arguments are variables. For example:

not_member(X, Ls) :- maplist(dif(X), Ls).


这个定义保留了对合的可交换性,正如我们对纯逻辑关系的深切期望和实际上期望一样:

?-not_member(X,[a,b,c]),X = d。
X = d。

?-X = d,not_member(X,[a,b,c])。
X = d。


由于not_member/2仅使用纯谓词,因此已经(通过构造)确保了它仅给出声明性正确的答案。

为了对您的代码进行声明式推理,我在您的方法中对此表示赞赏,建议您继续使用Prolog的纯单调子集。有关更多信息,请参见logical-purityprolog-dif

关于list - 如果直接插入Prolog,为什么会将变量与失败的结果匹配?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/33122122/

10-11 22:29
查看更多