Prolog:查询中的 'cut' 与 rules/facts

Prolog: 'cut' in query vs. rules/facts

learnprolognow 上做练习 10.4,有人可以向我解释或帮助我想象一下为什么 ?- p(X),p(Y) 我们得到:
X=1,Y=1; X=1,Y=2; X=2, Y=1; X=2, Y=1. 而且不只是 X=1, Y=1; X=1, Y=2.

我想我误解了剪切是如何发生的,当它在规则集中而不是查询中时 - 因为我认为我可以将它可视化为 ?- p(X),!,p(Y).,它的实际行为与我认为的最后一个一样会...

编辑:来自网站

% database
p(1).
p(2):-!.
p(3).

% Queries
p(X). % returns: X=1; X=2.
p(X),p(Y). % returns: X=1,Y=1; X=1, Y=1; X=2, Y=2. (?)
p(X),!,p(Y). % returns X=1, Y=1; X=1, Y=2.

要理解这个问题,您可以想象一棵树,其中 X 作为第一层,Y 作为第二层(prolog 使用可以用树很好地描述的 sld 分辨率)。考虑这个问题:

p(1).
p(2):-!.
p(3).

sol(X,Y):-
    p(X),
    p(Y).

我添加了谓词 solve/2 以使其更清楚。 运行 查询:

?- solve(X,Y).

首先您必须选择 X 的值。 Prolog使用从上到下,从左到右的深度优先搜索。所以它评估p(x)p(1)成功(因为是第一个子句,如果你在p(1)上面写p(2)p(2)就会成功)所以X = 1.然后评估 p(Y): p(1) 成功,所以你有第一个解决方案:

X = Y, Y = 1.

如果您点击更多,那么 prolog 会回溯(您可以将其想象为树上的一个步骤)并尝试 p(Y) 的另一个值。在这种情况下 p(2) 成功,谓词为真,你得到:

X = 1, Y = 2.

现在,如果您点击更多,由于 p(2) 的正文中有一个剪切点 (!)(prolog 中的一般规则的形式为 head :- body), 序言不会更深入, p(3) 被忽略。所以 p(Y) 没有更多的解决方案。所以还有另一个回溯,这次,p(X)p(2) 成功,X = 2p(Y)p(1) 成功,你得到:

X = 2, Y = 1.

如果你点击更多,你会得到:

X = Y, Y = 2.

现在,由于 p(2) 之后有一个剪切,XY 都没有更多可用的解决方案(! 剪切了下面的所有内容p(2)).

如果你删除切割你得到所有可能的解决方案:

X = Y, Y = 1
X = 1,
Y = 2
X = 1,
Y = 3
X = 2,
Y = 1
X = Y, Y = 2
X = 2,
Y = 3
X = 3,
Y = 1
X = 3,
Y = 2
X = Y, Y = 3

请记住,子句的顺序很重要。如果你写

p(2).
p(1):-!.
p(3).

你得到

X = Y, Y = 2
X = 2,
Y = 1
X = 1,
Y = 2
X = Y, Y = 1

您可以使用跟踪器检查此行为。在 SWI 或 SWISH 中,您可以编写 ?- trace, solve(X,Y).

如果您遇到这样的情况:

p(1).
p(2).
p(3).

sol(X,Y):-
    p(X),
    !,
    p(Y).

prolog 将测试 Y 的所有可能值,而 X 仅测试一个值,因为切割会停止对树的探索(理想情况下,X 有 3 个分支( 1,2,3) and 3 for Y (1,2,3), !X) 中减去 2 和 3 得到:

X = Y, Y = 1
X = 1,
Y = 2
X = 1,
Y = 3

抱歉了这么久post,希望清楚。