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

时间:2015-11-16 09:58:21

标签: prolog prolog-dif declarative-programming logical-purity

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

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

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

谢谢!

3 个答案:

答案 0 :(得分:3)

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

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

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

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

有关详细信息,请参阅

答案 1 :(得分:2)

特别是作为新手,尝试弃用不纯的构造并坚持

如何? 使用

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

答案 2 :(得分:1)

Prolog是一种基于特定resolution method编程语言,您描述的问题就是:程序中的问题(好吧,我称之为错误)。子句和目标的顺序如何控制算法:一系列步骤,对您的表示有明确的影响。然后关于这样的效果的知识是恕我直言不可避免的,并且 - 我认为 - 用\== / 2替换(dif)/ 2不会让你的生活更轻松,当你试图编码时更复杂的东西。至少,根据我的经验,当我必须建模并调试我的代码时,我遇到了额外的困难。

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

对于您的使用,(\=)/ 2可以提供更好的服务,但同样,为了简单使用,它需要两个参数都实例化。这是真的,取决于在整个“推理图”上,这是实际调用目标 - 操作语义。通常,确定谓词是否可以安全地使用特定模式调用并不简单(甚至可行)。考虑一下这个例子,我得到一个关于我的naive assertion - append / 3的评论,这是一个纯粹的Prolog库谓词,对所有的instatiation模式都是安全的:

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

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

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