从操作上,或者如果您愿意,从程序上解释,剪辑非常简单。然而,由于大多数关于逻辑编程和 Prolog 主题的文献都偏向于 Prolog 程序的 声明性 含义(有充分的理由),因此难以解释这种削减。纠正这种情况的一种尝试是根据效果对剪辑进行“着色”。
这是我试图让一切变得不那么清晰的尝试。
cut的操作意义,
来自SWI-Prolog's reference manual:“丢弃自输入出现切分的谓词以来创建的所有选择点。换句话说,提交切分出现的子句并丢弃由目标创建的选择点在当前子句中剪切的左侧。”
来自"The Art of Prolog" by Sterling and Shapiro:“目标成功并将 Prolog 提交给所有选择,因为父目标与发生剪切的子句的头部统一 [强调不是我的]。虽然这个定义是完整和精确的,但其后果和含义并不总是直观清晰或明显。”
来自"The Craft of Prolog" by O'Keefe:“[切割] 将选择点的堆栈修剪回调用包含切割的词法的谓词时所在的位置。另一种说法是 切割成功并将 Prolog 提交给自调用父目标以来所做的所有选择 [再次强调不是我的]"
我建议您至少从上面引用的两本书中阅读有关剪辑及其用途的部分。它肯定会帮助您了解实际情况。
一个常见的讨论是寻找解决方案与答案与证明之间的区别。我们(用户、程序员)通常需要答案。评估 Prolog 谓词的结果是解决方案。然而,Prolog 真正寻找的是证明。
以你为例。你有数据库p(1). p(2). p(3).。你现在想问 Prolog,“有没有 p(X) 这样 X =:= 3,
?- p(X), X =:= 3.
X = 3.
您会得到一个解决方案,X = 3。您的问题也会得到答案:是的,有这样一个p(X),X 是 3,显然没有更多答案了。
(尝试查询?- p(X), X =:= 2.。它的行为是否与原始查询相同?)
可以通过跟踪查询(以某种方式)看到您的证明树:
?- trace(p/1), trace(=:=).
% p/1: [call,redo,exit,fail]
% (=:=)/2: [call,redo,exit,fail]
true.
[debug] ?- p(X), X =:= 3.
T Call: (7) p(_G1004)
T Exit: (7) p(1)
T Call: (7) 1=:=3
T Fail: (7) 1=:=3
T Redo: (7) p(_G1004)
T Exit: (7) p(2)
T Call: (7) 2=:=3
T Fail: (7) 2=:=3
T Redo: (7) p(_G1004)
T Exit: (7) p(3)
T Call: (7) 3=:=3
T Exit: (7) 3=:=3
X = 3.
基本上,p/1 的每个子句都是依次尝试的。前两个没有产生证明,因为连词的第二个子目标失败了。每次从最后一个选择点(p/1 的下一个子句)开始搜索证明。最后一个可以被证明,你会得到一个解决方案和你的查询的答案。
现在您在p/1 的第二个子句的正文中添加了一个切口:p(1). p(2) :- !. p(3).。您告诉 Prolog(根据上面的定义 3.),“当搜索证明到达 p/1 的第二个子句时,将其参数与 2 统一的那个,修剪选择堆栈指向它的位置p/1 被调用。”当p/1 被调用时,没有选择点。因此,当X =:= 3 失败时,证明搜索完成,连词无法被证明,没有解决方案,你也得不到答案。
(尝试查询?- p(X), X =:= 2.。它是否与您没有剪辑时的相同查询相同?)
现在到 colors..... 在连词 p(X), X =:= 3. 的上下文中,这个剪切删除了一个解决方案和一个证明。你没有得到你期望的答案。这个切口是红色。
如果我们可以告诉 Prolog 我们的意思是切割为绿色或红色(或绿色或灰色或红色或蓝色),那就太好了,但 Prolog 不允许我们这样做。 “颜色”是程序的预期含义(程序员的意图)和剪辑的操作(程序)效果的结果。
但是说真的,试着买一本书并阅读关于剪辑的部分。甚至两本书。