2

我最近开始研究 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(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.

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

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

谢谢!

4

3 回答 3

3

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

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

dif/2改为使用纯粹且完全声明性的方式来说明术语的不相等性。

?- diff(X, Y), X = Y.
 false。

有关详细信息,请参阅

于 2015-11-16T10:04:07.287 回答
2

特别是作为新手,尽量避免使用不纯的结构并保持

如何? 使用

而不是X \== Y简单地写dif(X, Y).

于 2015-11-16T10:04:43.380 回答
1

Prolog是一种基于特定解决方法的编程语言,而您描述的问题就是:您的程序中的一个问题(好吧,我称之为bug)。子句和目标的顺序您控制算法的方式:一系列步骤,对您的表示具有明确的影响。然后,恕我直言,关于这种影响的知识是不可避免的,而且 - 我认为 -当您尝试编写更复杂的代码时,将( \== )/2替换为dif /2 不会让您的生活更轻松。至少,根据我的经验,当我不得不对代码进行建模和调试时,我遇到了额外的困难。

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

对于您的使用, ( \= )/2 会更好,但同样,为了简单的使用,这两个参数都需要实例化。这是真的,取决于目标的实际调用产生的整个“推理图”——操作语义。一般来说,确定一个谓词是否可以安全地使用特定模式调用并不简单(我认为甚至不可行)。考虑一下我得到的这个反例,作为对我的幼稚断言的评论- append/3,一个纯 Prolog 库谓词,对所有实例化模式都是安全的:

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

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

?- setof(R, relative(dave, R), Relatives), maplist(writeln, Relatives).
于 2015-11-16T14:47:43.717 回答