在這里我把書里比較有用的技巧做一下記錄吧,
1.4.2中講了尾遞回優化,
比如要求一個串列的長度,第一種代碼是這樣:
len([], 0).
len([_|Tail], N):-
len(Tail, M),
N is M + 1.
它沒什么不對,但運行時會生成堆疊框架塔,占用大量空間,每次往下遞回時,自然會?生成新的一個串列和變數,但問題在于,這個代碼會使得,直到串列清空、最深層的遞回回傳0,之前的這些串列及對應的值才能進行逐漸回傳,依次得到釋放,比如,一個串列為[1, 2, 3],將其匯入,對應的長度為N,然后開始第一次層遞回,關聯了新的串列[2, 3]及其對應的長度N0,N=N0+1;進行第二層遞回,匯入串列[2, 3],關聯新的串列[3],N0=N1+1;進行第三層遞回,匯入串列[3],關聯新的串列[],N1=N2+1;進行第四層遞回,匯入[],符合第1個陳述句,N2確定為0,遞回終止,至此,之前生成的串列和對應的長度都還存在,隨后,進行回傳,串列[3]對應的長度為1,串列[2, 3]對應的是2,串列[1, 2, 3]對應的是3,這才逐漸釋放,
而第二種代碼是這樣:
len(List, Length):-
len(List, 0, Length).
len([], N, N).
len([_|L], N0, N):-
N1 is N0 + 1,
len(L, N1, N).
首先,傳入len(List, Length),會變成len(List, 0, Length),然后后者如果不為空,會與len([_|L], N0, N)進行系結,Length等同于N,然后進行遞回,N0從0開始逐漸增大,而在完成最里層的遞回前,所有層的遞回N(Length)一直是占用同一個未知變數,當串列清空時,會與len([], N, N).陳述句系結,將中間的N的值系結給右邊的N,從而Length得到確定,比如串列[1, 2, 3],一開始得到len([1, 2, 3], 0, Length),第一次遞回后,得到得到len([2, 3], 1, Length),第二次遞回,得到len([3], 2, Length),第三次得到第二次遞回,得到len([], 3, Length),最后呼叫len([], N, N),遞回結束,Length的長度與中間的N系結,得以確定,
第一種代碼,即使運行完最里層的遞回依然沒有結束,還得依次從里往外回傳值,但第二種代碼,它每次往下遞回都能得出確切的值,當運行完最里層的遞回時,最外面層的未知變數同時得以確定,只用跑一趟,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/463516.html
標籤:其他
上一篇:第一天:基礎
下一篇:計算機網路3-物理層
