递归是Prolog中最本家儿要而又最难于把握的概念之一,Prolog是一门声明式编程说话,当你处置事物调集时,如列表或树,你会经常利用递归而不是迭代。
1的算术运算
1的调试
让我们先从这一个简单的例子来领会递归的性质吧。
在ancestor子句中的一个子句会利用ancestor子句。在这个例子中,ancestor(Z, Y)是一个递归的子方针。father 是实现递归子方针的焦点事实。法则ancestor/2有两个子句。
若是一个法则由多个子句构成,那么此中一个子句为真,则这个法则为真。可以把子句间的逗号算作是前提“与”的关系,把子句之间的句号算作是前提“或”的关系。
我们可以测试一下这个法则:
我们起首扣问命题ancestor(john_boy_sr, john_boy_jr).和ancestor(zeb, john_boy_jr).是否为真,接着给出变量Who,别离寻找zeb的儿女和john_boy_jr的祖先。
我们已经可以在常识库中利用这个法则实现两个目标:寻找祖先和儿女。
一个整数的阶乘界说为,该数与小于它的全数正整数的积,一个整型数的阶乘用该数及后面的感慨号暗示(!)。好比:5! = 5 × 4 ×3 × 2 × 1。一般形式为:
n! = n × (n - 1) × (n - 2) ×……× 3 × 2 × 1
然而,一个整型数的阶乘还可能暗示为这个整型数与公比其小1 的阿谁整型数的阶乘的乘积,例如:5!=5×4!。这种阶乘的界说体例就表现了递归,因为它操纵阶乘自界说阶乘。是以,任一正整数的阶乘可用下面递归界说给出:
n! = n × (n-1)!
在数学的界说上,0的阶乘等于1。是以,阶乘的完整界说如下:
0! = 1(遏制前提)
n! = n x (n - 1)!(递归界说)
转换当作Prolog法式如下图所示:
在扣问后,获得成果后按回车。运行成果如图所示。值得注重的是,在常识库中遏制前提应该放在递归法则前面,这一点是至关主要的。因为若是不是如许,遏制前提将永远不会知足。假如把法则放在遏制前提前面,那么Prolog反复进入常识库时将起首碰到它,并与其进行匹配,即使是应知足遏制前提时,也毫不会与遏制前提匹配,从而引起无限递归。
数学的斐波那契数列是一个正整数数列,它与黄金比例有着紧密亲密的联系。该数列的下一个数是由其前面两个数相加获得的,头两个数均为1。该数列如下:
1,1,2,3,5,8,13,21,34,55,……
通式为:
f(1) = 1 (两个遏制前提)
f(2) = 1
f(n) = f(n-1) + f(n-2) (递归法则)
这里用Num1、Num2这两个变量别离来暗示序数Num项的前面两项;变量Term1和Term2别离暗示前两项斐波那契数的成果。来转换当作Prolog法式如下图所示:
运行后的成果如下图所示。从截图可以看出,这些递归的法式还存在一些问题,好比在已经得出成果后,若是按“;”键试图查找另一个解时,会呈现错误的谜底,甚至起头报错。因为若是查找另一个成果,会从头进入递归前提,会再次减去数字,因而会报错。我将会鄙人次介绍Prolog的另一个机制——截断。
以上几个实例用于申明递归的Prolog法式。年夜大都较年夜的Prolog法式都可能包含递归,递归是年夜大都Prolog法式中的本家儿要节制手段。
在编写递归途序时,应服膺下述几点:
❶所有递归法则都必需有遏制前提,若是没有遏制前提,递归法则将无尽头地递归下去。
❷一般环境下,遏制前提应该放在常识库中递归法则的上方。因为若是总找不到遏制前提,也将导致无限递归。
❸凡是,在编写Prolog法式时应尽量采用递归,这要求自问如下问题:
➀是否可以把问题用其自身表达出来?
➁遏制前提是什么?
总的来说,递归法则具有下列一般形式:
递归法则的遏制前提.
递归谓词 :-
某些初始计较,
递归谓词,
某些最终运算.
0 篇文章
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!