自动回溯是Prolog中颇有表明性的一个特征。可是回溯可能会致使低效。有时Prolog会浪费时间在一些没有结果的可能性搜索上。若是在回溯行为方面有一些控制机制的话,会是一件比较有意义的事情,可是直到如今为止咱们看到只有两种至关初级的方式能够用于这个目的:交换规则顺序,和交换目标顺序。其实有另一种方式:存在一个内置的谓词:!(英文感叹号),称为中断,能够提供一种更为直接地控制Prolog搜寻解决方案的方式。学习
到底中断是什么,它是如何起做用的?它实际上是一个特殊的原子,咱们能够在子句中使用它。看例子:code
p(X) :- b(X), c(X), !, d(X), e(X).
上面的例子就是一个完美的Prolog规则。中断是这样起做用的:首先,它是一个永远成功的目标;其次,更为重要的是,它有一个反作用。假设有其余一些目标会使用这个子句(咱们称之为父目标,好比例子中的p(X)),在进行搜索时,中断会使得规则左边的目标没法回溯,而只能回溯规则右边的目标。让咱们经过例子来学习。blog
首先思考没有中断的代码:原理
p(X) :- a(X). p(X) :- b(X), c(X), d(X), e(X). p(X) :- f(X). a(1). b(1). b(2). c(1). c(2). d(2). e(2). f(3).
若是查询p(X),咱们会获得以下的答案:搜索
?- p(X). X = 1; X = 2; X = 3; false
下面是对应的搜索树,注意其中必须回溯的地方,当进入第二个子句,决定知足第一个目标b(1),回溯后被替换为b(2)。程序
如今假设咱们在第二个子句中加入中断:im
p(X) :- b(X), c(X), !, d(X), e(X).
若是如今查询p(X),会获得以下的答案:d3
X = 1; false
这里发生了什么?让咱们思考一下。查询
若是观察以下的搜索树,你会发现一些树枝被删除:当目标d(1)不能在进行,可是须要回溯寻找新的选择时,搜索已经被中止:db
有一个须要强调的要点:中断会提交全部的选择,这些选择是为了知足父目标而将包含中断的子句合一时作出的,而且是从中断左端进行合一的那些选择。好比,在以下规则的模式中:
q :- p1, ..., pn, !, r1, ..., rm
当咱们到达中断的时候,Prolog会提交为了知足q的而且包含中断的子句的全部选择,而且这些选择是运算p1, ..., pm得出的。然而,在r1, ..., rm内,咱们可以进行回溯,而且知足目标q以前的其余选择咱们也能够进行回溯。经过看下面的例子来明确这些原理。
首先思考没有中断的程序:
s(X, Y) :- q(X, Y). s(0, 0). q(X, Y) :- i(X), j(Y). i(1). i(2). j(1). j(2). j(3).
以下是查询和结果:
?- s(X, Y). X = 1 Y = 1; X = 1 Y = 2; X = 1 Y = 3; X = 2 Y = 1; X = 2 Y = 2; X = 2 Y = 3; X = 0 Y = 0; false
下面是对应的搜索树:
假设咱们在q/2子句中加入中断:
q(X, Y) :- i(X), !, j(Y).
如今程序的行为以下:
?- s(X, Y). X = 1 Y = 1; X = 1 Y = 2; X = 1 Y = 3; X = 0 Y = 0; false
让咱们看看为何:
以下式对应的搜索树: