我正在通过七周的七种语言工作,但有一些我对prolog不了解。我有以下程序(基于他们的华莱士和格罗米特计划):
/* teams.pl */
onTeam(a, aTeam).
onTeam(b, aTeam).
onTeam(b, superTeam).
onTeam(c, superTeam).
teamMate(X, Y) :- \+(X = Y), onTeam(X, Z), onTeam(Y, Z).
并像这样加载
?- ['teams.pl'].
true.
但它没有给我任何解决方案以下
?- teamMate(a, X).
false.
它可以解决更简单的东西(在书中显示):
?- onTeam(b, X).
X = aTeam ;
X = superTeam.
并且有解决方案:
?- teamMate(a, b).
true ;
false.
我错过了什么?我尝试过使用gnu prolog和swipl。
......还有更多......
当你移动“不能成为你自己的队友”限制然后结束时:
/* teams.pl */
onTeam(a, aTeam).
onTeam(b, aTeam).
onTeam(b, superTeam).
onTeam(c, superTeam).
teamMate(X, Y) :- onTeam(X, Z), onTeam(Y, Z), \+(X = Y).
它为我提供了我期望的解决方案:
?- ['teams.pl'].
true.
?- teamMate(a, X).
X = b.
?- teamMate(b, X).
X = a ;
X = c.
是什么给出了?
答案 0 :(得分:6)
你做了很好的观察!事实上,情况更糟,因为即使是最常见的查询也会失败:
?- teamMate(X, Y). false.
声明地说,这意味着“没有任何解决方案”,这显然是错误,而不是我们期望关系如何表现:如果有解决方案,那么更通用查询一定不能失败。
你得到这种奇怪且逻辑上不正确的行为的原因是(\+)/1
只有在其参数充分实例化时才会发出声音。
以更一般的方式表达不平等的术语,无论参数是否被实例化,正确地使用,使用 dif/2
,或者,如果您的Prolog系统未提供,则可以在 prolog-dif 标记中找到安全近似值iso_dif/2
。
例如,在您的情况下(note_that_I_am_using_underscores_for_readability
而不是tuckingTheNamesTogetherWhichMakesThemHarderToRead
):
team_mate(X, Y) :- dif(X, Y), on_team(X, Z), on_team(Y, Z).
您的查询现在完全符合预期:
?- team_mate(a, X). X = b.
最常见的查询当然也可以正常运行:
?- team_mate(X, Y). X = a, Y = b ; X = b, Y = a ; X = b, Y = c ; etc.
因此,使用dif/2
来表达不平等会保留您关系的 logical-purity :系统现在不再简单地说false
即使有溶液。相反,你会得到你期望的答案!请注意,与之前相比,无论您拨打电话的位置,都可以使用!
答案 1 :(得分:3)
answer by mat为您提供了一些高级考虑因素和解决方案。我的答案更多地是关于潜在的原因,可能会或可能不会让你感兴趣。
(顺便说一句,在学习Prolog的过程中,我几乎问了the same question并得到了同一个用户very similar answer。很棒。)
你有一个问题:
两名球员是队友吗?
要从Prolog获得答案,请制定一个查询:
?- team_mate(X, Y).
其中X和Y都可以是自由变量或绑定。
基于您的谓词数据库(事实和规则),Prolog尝试查找证明并为您提供解决方案。 Prolog searches for a proof by doing a depth-first traversal of a proof tree。
在您的第一个实现中,\+ (X = Y)
先于其他任何内容,因此它位于树的根节点,并将在以下目标之前进行评估。如果X
或Y
是自由变量,X = Y
必须成功,这意味着\+ (X = Y)
必须失败。因此查询必须失败。
另一方面,如果X
或Y
是自由变量,dif(X, Y)
将成功,但稍后会尝试将它们统一起来其他必须失败。此时,Prolog将不得不在证明树的另一个分支上寻找证据,如果还有剩下的话。
(考虑到证明树,试着想出一种实现dif/2
的方法:你认为没有a)在dif/2
或\+ (X = Y)
的参数中添加某种状态是可能的吗? b)改变决议策略?)
最后,如果你将X
放在最后,并注意Y
和{{1}}在评估时都是基础的,那么统一就会变得更像一个简单的比较,可能会失败,因此否定可以成功。