SWI-Prolog的截断机制

时间:2024-10-11 18:58:44

我们经常会在Prolog的递归中用到截断。尽管回溯是Prolog中最有用的机制之一,但有时我们希望利用截断控制回溯的程序。在这篇经验中,我将介绍截断机制与谓词fail。

SWI-Prolog的截断机制

工具/原料

电脑

SWI-Prolog

保证正确地选择规则

1、Prolog为用户提供了一种可存在于程序中并控制回溯水平的机制,即所谓的“截断(cut)”。Por造婷用痃log中用叹号“!”表示截断。当在几个目标合取中设置了截断时,其作用就好似安上了一扇单向门。截断作为目标总是成功的,且不能重复满足。例如,下面的规则:example :- a, b, c, !, d, e, f.Prolog可以在目标a、b、c之间任意回溯,但一旦目标c一经满足,将通过截断符号,然后Prolog继续沿着目标链试图满足目标d、e、f,回溯可能在d、e、f之前进行,然而不能通过“!”回溯前面的,即使导致总体目标example失败也是如此。

SWI-Prolog的截断机制

2、程序中一个谓词常常以多种形式存在,其中一般至少有两种不同形式的谓词丰硕,即递归规则和停止条件。当编写这样的谓词时,必须保证Prolog总是选择谓词的正确形式。如当Prolog应当采用停止条件时,就不应选择递归规则,否则会导致无穷递归。例如,下面这个程序是用于计算X的Y次幂。

SWI-Prolog的截断机制

3、如果我们对Prolog提出询问:?- power(2,3,Result).将会以以下方式进行操作:2³ = 2² * 2,2² = 2¹ * 2,2¹ = 2⁰ * 2,且2⁰ = 1。

SWI-Prolog的截断机制

4、但如果我们要求上例在给出回答后继续回溯,即键入分号,则会试图在知识库中寻找到另一个事实或规则,使其爵奏笆棚与上面的目标匹配。这就是说,Prolog搜索到的另一个Prolog谓词便是递归规则。Prolog与之匹配,使X为2,Y为0,然后Prolog计算Y_tmp得到-1,并试图满足目标:power(X, Y_tmp, Pow_tmp),这等于在计算2⁻¹,依次进行下去,将试图计算2⁻²,2⁻³,等等。这时无穷递归出现了,即递归目标连续产生自己,而永远不能满足停止条件,开始报错。

SWI-Prolog的截断机制

5、上面的情况显然不是我们所期望的,它可以通过在停止条件中设置截断而得以避免,这样就得到了下列新的、更瑕铆幌约加健全和可靠的power谓词形式:power(_, 0, 1). :- !.power(X, Y, Pow) :- Y_tmp is Y - 1, power(X, Y_tmp, Pow_tmp), Pow is Pow_tmp * X.这里截断符号表示“如果已经选择了某个规则,那么决不允许回溯并选择同一谓詞的其他规则”。因此,这将会产生合理结果。

SWI-Prolog的截断机制
SWI-Prolog的截断机制

6、此时我们可能已经意识到上一节中给出的两递归规则也会产生类似的、不希望的结果,而这可以通过在它们的停止条件中分别加入截断而加以避免。加入截断后的程序如图所示。总而言之,如果在停止条件处可能用到递归规则,那么必须在递归谓词的停止条件中加入截断符号。

SWI-Prolog的截断机制
SWI-Prolog的截断机制

截断与谓词fail的联用

1、截断的另一个常用方式是与谓词fail联用。fail是一个Prolog标准谓词,由于它总是失败,因而可引起回溯。截断可设置在fail前面,以防止失败后的回溯。考虑图中的程序。这里截断与fail联用可以保证当一个雇员满足某个表明其不符合候选条件的规则时,在其它任何规则都不再考虑。例如,一个员工小于50岁,谓词fail将使目标eligible失败,而截断则保证在其它两个eligible规则中都不考虑他。

SWI-Prolog的截断机制

2、应当注意,截断与fail联用通常可用否定谓词“\+”代替,\+是Prolog另一个标准谓词,如果目标X失败,则目标\+(X)成功;如果X成功,则会失败。因此上面程序可以重写为图片中的形式。这里把三个eligible规则合成为一个规则,这两种编程方式中哪种可读性更高呢?关于这一问题存在争议,因为这取决于对截断的理解程度。

SWI-Prolog的截断机制

利用截断控制回溯程度的原因

1、尽管回溯是Prolog语言中最有用的机制之一,但基于下述理由,有时我们希望控制回溯的程度:❶我们可能不希望Prolog得出问题的全部解,因为有些解对我们来说可能没有任何用处;❷一旦找到一个特定的解,就没有必要去找其它更多的解,而其它解可能实际上是不正确的;❸大量回溯会使程序运行的效率很低,其中有两个原因,一是回溯要花费一些时间才能完成,二是回溯中Prolog所做的标记要占用大量的计算机内存。

SWI-Prolog的截断机制
© 手抄报圈