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

Mar*_*utz 5 predicate prolog 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).
Run Code Online (Sandbox Code Playgroud)

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

| ?- ['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
Run Code Online (Sandbox Code Playgroud)

这一切都符合预期.现在,我想在查询中引入一个变量.我的意图是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}
Run Code Online (Sandbox Code Playgroud)

它甚至没有尝试统一X(_16)grommit.为什么?

Phi*_* JF 4

这是朋友的定义:

friend(X, Y) :- \+(X = Y), likes(X, Z), likes(Y, Z).
Run Code Online (Sandbox Code Playgroud)

这里重要的是你从\+(X = Y)通常定义为:

\+ Goal :- Goal,!,fail
Run Code Online (Sandbox Code Playgroud)

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

反而

friend(X, Y) :-  likes(X, Z), likes(Y, Z), \+(X = Y)
Run Code Online (Sandbox Code Playgroud)

会表现得更符合你的预期。

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