鉴于以下事实和谓词:
sound(time1).
sound(time2).
sun(time3).
relax(X):-sound(X),!,sun(X).
relax(_):-sun(_).
执行relax(S).
时,由于S=time1
,我希望得到!
,如果我错了,请说明(如果我错了),如果满足'X',然后停止回溯。
这是跟踪:
3 ?- trace.
true.
[trace] 3 ?- relax(S).
Call: (6) relax(_G1831) ? creep
Call: (7) sound(_G1831) ? creep
Exit: (7) sound(time1) ? creep
Call: (7) sun(time1) ? creep
Fail: (7) sun(time1) ? creep
Fail: (6) relax(_G1831) ? creep
false.
那么为什么Prolog也会检查sun(time1)
,即使它在被sound(X)
满意后遇到感叹号(因为sound(time1)
是事实)。
答案 0 :(得分:26)
!
符号可以防止左侧的条款向后移动,它就像一个单向门,因此它不会在切割之后回溯。
当sound(time1)
为真时,将评估下一个句子sun(time1)
,然后只有prolog会发现sun(time1)
是false
(通过搜索知识库,它实际上并不知道这是事实。)
然后,由于剪切,prolog不会在第一个子句中尝试值time2
和time3
。
关于剪切的更多信息:
Prolog从左到右评估谓词的子句。它将值绑定到最左边子句中的变量。如果该子句是true
,则它将移至下一个子句。如果它是false
,prolog也会尝试其他值。
如果任何值都不能满足任何条款,那么它将是false
,因此将是整个谓词(因为子句由AND连接)。
整个事物作为树的深度优先遍历,其中子句是节点,边表示其变量的不同值。如果遍历发现一个子句为false
,它将返回其前一个子句并尝试不同的值。
这是剪辑。如果你在两个子句之间放置一个剪切(!
),这意味着如果一个剪切后的子句成为false
,那么只有在评估时才会尝试新值切割后运行。这意味着在剪切之前使用的变量的值已锁定,并且当评估越过剪切时,它们无法更改。
答案 1 :(得分:21)
为了更清楚地说明这一点,如果有人仍在努力解决感叹号运算符的工作方式(就像我做的那样),这里有一个例子:
sound(time3).
sound(time1).
sun(time1).
relax(X):-sound(X),!,sun(X).
对于这个特定的例子,如果您向Prolog询问?-relax(S).
,则结果为 false 。我们可以用这样的方式描述Prolog:
反对,就像我在4.中所说的那样!运营商会导致成功。
sound(time3).
sound(time1).
sun(time1).
relax(X):-sound(X),sun(X).
如果我在某些方面错了,请随时纠正我。
答案 2 :(得分:4)
它仍然会尝试满足规则的其余部分,它不会在感叹号之前回溯。也就是说,如果sun(X)
失败,它将不会回溯并尝试将不同的对象与sound(X)
匹配,但无法完全匹配该规则。