带有变量的Prolog查询中的`\ +`问题

时间:2011-05-12 00:09:08

标签: prolog predicate gnu-prolog

我正在阅读“7周内七种语言”的内容,我对Prolog的一些问题感到困惑,因为我不理解“不”的回应。

friends.pl文件如下所示:

likes(wallace, cheese).
likes(grommit, cheese).
likes(wendolene, sheep).

friend(X, Y) :- \+(X = Y), likes(X, Z), likes(Y, Z).

我可以对它做一些简单的查询,例如:

| ?- ['friends'].
compiling /home/marc/btlang-code/code/prolog/friends.pl for byte code...
/home/marc/btlang-code/code/prolog/friends.pl compiled, 12 lines read - 994 bytes written, 8 ms

yes
| ?- friend(wallace,grommit).

yes
| ?- friend(wallace,wendolene).

no

这一切都符合预期。现在,我想在查询中引入一个变量。我的意图是Prolog会给我一份华莱士所有朋友的名单。我期待X = grommit,但我得到no

| ?- trace.
The debugger will first creep -- showing everything (trace)

yes
{trace}
| ?- friend(wallace,X).
      1    1  Call: friend(wallace,_16) ?
      2    2  Call: \+wallace=_16 ?
      3    3  Call: wallace=_16 ?
      3    3  Exit: wallace=wallace ?
      2    2  Fail: \+wallace=_16 ?
      1    1  Fail: friend(wallace,_16) ?

no
{trace}

它甚至没有尝试将X_16)与grommit统一起来。为什么?

4 个答案:

答案 0 :(得分:4)

这是朋友的定义:

friend(X, Y) :- \+(X = Y), likes(X, Z), likes(Y, Z).

重要的是你从\+(X = Y)开始,通常定义为:

\+ Goal :- Goal,!,fail

请注意,这意味着如果目标成功,您肯定会失败。自由变量(未分配的变量)将始终统一,因此相等,因此您将始终使用自由变量失败。因此,如果它还没有值,它将永远不会为X或Y赋值。

相反

friend(X, Y) :-  likes(X, Z), likes(Y, Z), \+(X = Y)

会表现得像你期望的那样。

这里的问题是prolog为您提供了强大的方法来控制程序的流程,但那些不太适合其更多的逻辑导向设计。应该可以以不产生这些问题的方式表达“否定为失败”类型约束。由于这个原因,我不是一个巨大的序幕粉丝。

答案 1 :(得分:4)

关于Philip JF上面的评论:

  

应该可以表达   “否定为失败”类型约束   以一种不产生这些的方式   问题。

这是可能的:这些问题的现代解决方案是限制。在这种情况下,使用例如dif/2,在所有严肃的Prolog系统中都可用。

答案 2 :(得分:3)

friend/2的第一个子目标是\+(X = Y)。这是通过首先尝试找到X = Y的解决方案,然后否定该结果来执行的。谓词=/2大致等同于unify/2,即它尝试将左操作数与右操作数统一。现在,当您使用例如询问查询时friend(wallace, gromit),两个原子wallacegromit不统一;但是当一个自由变量被抛入混合中时,它总是与给定的任何术语统一,因此X = Y总是成功的,因此\+(X = Y)总是失败,并且执行永远不会超过第一个子目标。< / p>

答案 3 :(得分:1)

首先使用不等式约束的另一个问题是:找到未绑定X的绑定是不可行的(不包括暂时将其与grommit统一的简单情况)。 Prolog通过运行其数据库找到绑定,尝试统一未绑定的变量。这就是为什么likes(grommit, Z)会找到Z的一些绑定然后可以进一步处理的原因,因为数据库中有likes个子句。但是对于某些事物的不平等没有这样的条款,所以Prolog不能产生任何约束力。事实上,friend谓词必须确保在测试不等式之前绑定所有变量。