Prolog规则中的目标(语句)顺序

Order of goals(statements) in Prolog rules

最近开始研究Prolog,遇到一个奇怪的问题。 在这里您可以看到一个代码示例(我使用 SWI-Prolog 7.2.3),它给出了关系树和我对 2 个任务的解决方案。

/*   File:    ancestors.pl
 Author:  Dave Robertson
 Purpose: Relationships in a family tree

Suppose we have a family tree like this :

alan andrea   bruce betty      eddie elsie   fred  freda
 |     |        |     |          |     |       |     |
 |_____|        |_____|          |_____|       |_____|
    |              |                |             |
  clive        clarissa            greg         greta
   |  |__________|___|              |             |
   |__________|__|                  |_____________|
          |   |                            |
        dave doris                        henry

which is defined in Prolog by the following 3 sets of predicates:

*/

%   parent(Parent, Child).
%   Parent is the parent of Child.

parent(alan, clive).
parent(andrea, clive).
parent(bruce, clarissa).
parent(betty, clarissa).
parent(clive, dave).
parent(clarissa, dave).
parent(clive, doris).
parent(clarissa, doris).
parent(eddie, greg).
parent(elsie, greg).
parent(fred, greta).
parent(freda, greta).
parent(greg, henry).
parent(greta, henry).

%%   PROBLEM 1
%%   How do you find out if someone is the ancestor of someone else ?
ancestor(X,Y) :- parent(X,Y).
ancestor(X,Y) :- parent(X,Z), ancestor(Z,Y).

%%   PROBLEM 3
%%   How do you know if someone is related to someone else ?
relative(X,Y) :-  ancestor(X,Y).
relative(X,Y) :-  ancestor(Y,X).
relative(X,Y) :-  ancestor(Z,X), ancestor(Z,Y), X\==Y.

当我想得到戴夫的亲戚时,我会这样做:

relative(dave,X).
X = clive ;
X = clarissa ;
X = alan ;
X = andrea ;
X = bruce ;
X = betty ;
X = doris ;
X = doris ;
X = clive ;
X = doris ;
X = clive ;
X = doris ;
X = clarissa ;
X = doris ;
X = clarissa ;
X = doris ;
false.

然后我改变我对 relative 的定义:

relative(X,Y) :-  ancestor(X,Y).
relative(X,Y) :-  ancestor(Y,X).
relative(X,Y) :-  X\==Y, ancestor(Z,X), ancestor(Z,Y).

我只是简单地改变了最后一句话中目标的顺序。 现在我有以下输出:

relative(dave,X).

X = clive ;
X = clarissa ;
X = alan ;
X = andrea ;
X = bruce ;
X = betty ;
X = dave ;
X = doris ;
X = dave ;
X = doris ;
X = clive ;
X = dave ;
X = doris ;
X = clive ;
X = dave ;
X = doris ;
X = clarissa ;
X = dave ;
X = doris ;
X = clarissa ;
X = dave ;
X = doris ;
false.

我在输出中看到了 dave!这怎么发生的?我写了 X \== Y... 谁能给我一个很好的解释?

还有一个问题。如何让我的程序不写出相同的答案?

谢谢!

(\==)/2不是纯粹的关系,只能从操作上理解。如果你使用它,交换目标的顺序可能会产生声明错误的结果:

?- X \== Y, X = Y.
X = Y.

请改用 dif/2 以纯粹且完全声明的方式来陈述术语的不平等。

?- dif(X, Y), X = Y.
false.

有关详细信息,请参阅

尤其是新手,尽量戒除不纯的构造,坚持!

怎么样? 使用!

而不是 X \== Y 只需写 dif(X, Y).

Prolog 是一种基于特定 resolution method, and the problem you describe is just that: a problem (well, I would call it a bug) in your program. The order of clauses and goals is how you control your algorithm: a sequence of steps with defined effects on your representation. Then a knowledge about such effects is IMHO unavoidable, and - I think - replacing (\==)/2 by dif/2 的编程 语言,当您尝试编写更多代码时,它不会让您的生活更轻松复杂的。至少,根据我的经验,当我不得不建模和调试我的代码时,我面临着额外的困难。

(\==)/2 旨在简化元编程,当您需要比较 variables 以获得身份时。因此,它实际上是一个相当高级的功能,您的程序不需要。但是(可能是因为它与 C/C++/Java 运算符非常相似),很容易低估它的用途。

供您使用,(\=)/2 would serve better, but again, it requires, for a simple use, that both arguments are instantiated. This being true, depends on the whole 'inference graph' resulting from the actual calling of goals - the operational semantic. Generally, it's not simple (or even feasible, I think) to determine if a predicate is safe to call with a specific pattern. Consider this counterexample I got as a comment about a my - append/3,纯 Prolog 库谓词,对所有实例化模式都是安全的:

?- append(Xs,[a],Xs).

为了避免重复并列出结果,我会使用 setof/3

?- setof(R, relative(dave, R), Relatives), maplist(writeln, Relatives).