【ProLog】5.0 计算与大小比较

【概述】
在ProLog中,我们用“is”代表“=”。如下图所示 :

同时,我们也可以在问询中提问有关算术结果的内容,比如:

我们可以通过定义来添加一种算法(有点其它语言方法函数内味了),比如
addThreeAndDouble(X, Y):-Y is (X+3) * 2.

那么我们在接下来的问询中,就可以使用这个定义了

?- addThreeAndDouble(1,X).
 X=8 
 yes 
?- addThreeAndDouble(2,X).
 X=10 
 yes  

【使用与进一步解释】
在前文已经说明了,ProLog中is才算是赋值号,而=并不是。因为在一般情况下,ProLog只会将诸如3+2,5-1这种运算式子当成普通的表达式

?- X = 3 + 2. 
 X = 3+2
 yes  

(显然没有做什么有意义是事情)
为了强制ProLog作运算,我们需要使用is !!
is在ProLog中并不是简简单单的一个谓词,它的使用存在着许多限制

对于在is右边的变量,我们可以自由地定义与使用他们。当ProLog在进行计算的时候,必须使用无变量的Prolog术语实例化变量,换句话说就是
is右边的变量必须是一个运算表达式,比如3+2

其它七七八八的说明:
关于3+2这样的写法实质上是针对用户的写法,在ProLog内部,它们实质上是+(3,2);is也是一个谓词,当我们进行“X is 3+2”时,实质上是:

?- is(X,+(3,2)).
  X = 5
  yes  

【运算与列表 Arithmetic and Lists 】
可以利用下面这行码来计算一个List的长度

原理是通过
len([_|L],N):-len(L,X),N is X + 1.
达到“从最后一位切割List,并记录下切割次数”的效果,然后通过Base条件
len([],0).
确认空List的长度是0
通过上面的两行,我们就作出看计算List长度的方法了

【“累加器” Accumulators 】
累加器Accumulators 是另外一种计算List长度的方法
对于这种方式,我们称它为“acclen/3”,它会包含三个部分:要计算长度的List,List的长度,以及一个“累加器”
1.累加器的初始值为0
2.我们利用递归,不断取List的头,然后1加到累加器上
3.当我们最终得到空List时,累加器就记录下了List的长度

acclen([],Acc,Length):-       
                      Length = Acc.  //当得到一个空List时,便是结束,此时Acc累加器的数值 = List 长度

acclen([_|L],OldAcc,Length):-
                      NewAcc is OldAcc + 1,  //每次我们从列表中减去一个头时,向累加器加1
                      acclen(L,NewAcc,Length).  
?-acclen([a,b,c],0,Len).
 Len=3 
 yes  

这次步骤的示意图如下,可以更好的帮助理解:

Plus:增加一个包装器

acclen([ ],Acc,Acc).
acclen([ _|L],OldAcc,Length):-
                             NewAcc is OldAcc + 1,     
                             acclen(L,NewAcc,Length). //在这进行累加器的运算,而在真正问询的时候,隐去累加器的参数
length(List,Length):-       
                     acclen(List,0,Length).           //利用length问询,就可以更简洁地得到两个我们想知道的参数

//acclen->递归 ->累加器计算->给予length的值->得到答案

【尾递归 Tail recursion 】
我们上文所用于计算List长度的acclen/3就是尾递归,它们的特点在于:
1.在尾部递归谓词中,一旦我们到达基本情况BaseCase,就会得到最终的总结结果
2.在非尾递归的递归谓词中,当我们到达基本BaseCase时,堆栈上仍有目标

len/2 之前的非尾部递归计算List长度的分析图

acclen/3 的分析图

【数值比较】
ProLog中的数值比较,和其它的语言也略有不同,具体见下图:

值得注意的是,在Prolog中进行比较的时候。两边的式子都是“有主要意义的”,左右两边的式子都会强制被计算,而不需要通过is

【利用比较来寻找数组中的最大值】
我们可以通过下面的思路实现:
1.有一个变量用于记录最大值
2.遍历数组

accMax([H|T],A,Max):-      
                    H > A,     
                    accMax(T,H,Max). 

accMax([H|T],A,Max):-      
                    H =< A,     
                    accMax(T,A,Max). 

accMax([],A,A).  

和之前的计算List长度一样,我们也可以给其增加一个包装器来提升美观

accMax([H|T],A,Max):-      
                    H > A,     
                    accMax(T,H,Max). 

accMax([H|T],A,Max):-      
                    H =< A,     
                    accMax(T,A,Max). 
                    accMax([],A,A). 

max([H|T],Max):-     
                    accMax(T,H,Max).  
posted @ 2021-04-18 20:10  RetenQ  阅读(475)  评论(0编辑  收藏  举报