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 = 2
和 p(Y)
,p(1)
成功,你得到:
X = 2, Y = 1.
如果你点击更多,你会得到:
X = Y, Y = 2.
现在,由于 p(2)
之后有一个剪切,X
和 Y
都没有更多可用的解决方案(!
剪切了下面的所有内容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,希望清楚。
在 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 = 2
和 p(Y)
,p(1)
成功,你得到:
X = 2, Y = 1.
如果你点击更多,你会得到:
X = Y, Y = 2.
现在,由于 p(2)
之后有一个剪切,X
和 Y
都没有更多可用的解决方案(!
剪切了下面的所有内容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,希望清楚。