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.为什么?
这是朋友的定义:
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 的忠实粉丝。