Learn Prolog Now 翻譯 - 第三章 - 遞迴 - 第二節,規則順序,目標順序,終止

來源:互聯網
上載者:User

標籤:

內容提要

 規則順序

 目標順序

 終止

 

 Prolog是第一門比較成功的邏輯程式設計語言。邏輯程式設計語言內在實現是簡單和富有魅力的:程式員的工作簡單地說就是描述問題;程式員應該寫下(使用語言的邏輯)聲明性的規格說明

(即,一個知識庫),去描述有趣的狀態、事實和關係;程式員不應該告訴電腦如何去實現,而他根據問一些問題去擷取資訊,邏輯程式設計語言會給出答案。

 然而,以上是理想情況,Prolog本身也確實通過一些重要的特徵,往這個方向在努力。但是Prolog不是,重複一次,不是一門完整的邏輯程式設計語言。如果你只是從聲明性方面去思考

Prolog程式,那麼實際使用上去就會十分困難。正如我們之前章節學習到的,Prolog通過特有的方式得出查詢的結果:它會自上而下地搜尋知識庫,從左至右地匹配每個子句的目標,並且

通過回溯從錯誤選擇中進行恢複。這些程式性的方面對你的查詢實際如何進行有很重要的影響。我們已經看過了一些例子在其聲明性和程式性上不匹配(記得 p :- p嗎?),接下來,我們

會繼續看到,Prolog中很容易定義邏輯上相同的,但是實現上卻十分不同的程式。讓我們思考如下的情況。

 

 請回憶之前我們定義的“後輩”程式,這裡我們稱為descend1.pl:

child(anne, bridget).child(bridget, caroline).child(caroline, donna).child(donna, emily).descend(X, Y) :- child(X, Y).descend(X, Y) :- child(X, Z), descend(Z, Y).

 這裡我們做一個調整,並稱新的程式為descend2.pl:

child(anne, bridget).child(bridget, caroline).child(caroline, donna).child(donna, emily).descend(X, Y) :- child(X, Z), descend(Z, Y).descend(X, Y) :- child(X, Y).

 這裡的修改只是換了一些兩個規則的順序。所以如果只是從純粹的邏輯定義上去理解,是什麼都沒有改變的。但是這種改變帶給程式性上有什麼不同嗎?是的,但不明顯。

比如,如果你查詢所有的情況,將會看到descend1.pl的第一個回答是:

 X = anne

 Y = bridget

 然而descend2.pl的第一個回答是:

 X = anne

 Y = emily

 但是兩個程式產生的答案是相同的,只是順序不一致。這是具有共性的。簡要地說,改變Prolog程式中規則的順序,不會改變程式的行為。

 

 我們繼續,在descend2.pl的基礎上,再進行一點小的修改,變成descend3.pl:

child(anne, bridget).child(bridget, caroline).child(caroline, donna).child(donna, emily).descend(X, Y) :- descend(Z, Y), child(X, Z).descend(X, Y) :- child(X, Y).

 

 請注意不同之處。這裡我們對一個規則中的目標順序進行了調整,而並非調整規則的順序。現在,如果我們純粹是從邏輯定義方面去理解,並沒有任何不同,這和之前的兩個定義

是一樣的含義。但是這個程式的行為已經徹底改變。比如,如果我們進行查詢:

 ?- descend(anne, emily).

 Prolog會報錯(類似“Out of local stack”)。Prolog進入了死迴圈,為什嗎?為了滿足查詢descend(anne, emily),Prolog會使用第一個規則。這意味著下一個目的是滿足查詢:

 descend(W1, emily).

 這裡引入了新的變數W1。但是為了滿足這個新目標,Prolog又會使用第一個規則,這意味著下一個目標會是:descend(W2, emily),這裡引入了新的變數W2。當然,就會迴圈引入下

一個新的目標descend(W3, emily),接下去又是descend(W4, emily),等等。即,目標順序的改變導致了程式的崩潰。使用標準的術語,這裡我們有一個經典的關於左遞迴規則的例子,

即一個規則的主幹部分最左端的目標是和規則的頭部一樣的。正如我們的例子所示,這種規則會導致非終止的計算。目標順序,特別是左遞迴,當其不能終止時,就會變成一切罪惡之源。

 

 還有,這裡有一個針對規則順序的提醒。我們之前提及規則順序的改變,只會影響其查詢的結果的順序。但是這個結論在非終止程式中是不適用的。為了說明這點,請參考關於“後輩”

代碼的第四次修改,稱為descend4.pl:

child(anne, bridget).child(bridget, caroline).child(caroline, donna).child(donna, emily).
descend(X, Y) :- child(X, Y).
descend(X, Y) :- descend(Z, Y), child(X, Z).

 

 這個程式只是在descend3.pl的基礎上,調整了規則的順序。現在這個程式和其他之前的程式具有一樣的聲明性含義,但是程式性上有所差別。首先,很明顯的是,和descend1.pl和

descend2.pl有明顯的差別,因為descend4.pl包含了左遞迴的規則,它會在進行一些查詢時無法終止計算。比如,我們如果進行下面的查詢,將無法終止計算:

 ?- descend(anne, emily).

 但是descend4.pl在程式性上和descend3.pl也有所不同。規則順序的不同導致了這種差異性。比如,descend3.pl在進行查詢:

 ?- descend(anne, bridget).

 時不會終止;但是descend4.pl在這個查詢中會有結果。因為它會首先使用非遞迴的規則,並且找到答案,終止計算。所以在非終止的程式中,規則順序的改變會導致找到一些額外的

解決方案。但無論如何,目標順序的改變,而非規則順序的改變,會使得程式性完全不同。為了確保計算能夠終止,我們必須注意規則主幹部分的目標順序。因為調整規則的順序,不會

改變非終止程式的本質——最多可以找到一些額外的解決方案而已。

 

 總結一下,以上四個關於“後輩”程式的變種,描述了同樣的問題,但是具體實現上有所不同。descend1.pl和descend2.pl在實現上的不同相對來說比較小:它們會產生相同的解決方案,

但是順序不同。然而descend3.pl和descend4.pl在程式性上的差異和之前兩個更大,因為它們的規則中目標的順序不同。具體而言,這兩個版本都包含了左遞迴規則,都會導致非終止的計算

行為。descend3.pl和descend4.pl在規則順序上有所不同,意味著在某些情況下,descend4.pl可以終止計算,但是descend3.pl不能。

 那麼我們如何構建有用的Prolog程式呢?通常你首先需要通過聲明性思考去確定整體的想法(藍圖),即思考如何精確地描述問題。這是解決問題的優先方式,同時也是邏輯編程的靈魂。

但是一旦你完成了這部分工作,就必須結合Prolog的具體實現檢查你的方案。特別是需要檢查規則中目標的順序,從而確保計算能夠終止。規則絕不要寫出規則的主幹最左邊目標和規則頭部

相同的情況,而是應該將觸發遞迴的目標寫到主乾的最右邊,即讓遞迴目標出現在所有非遞迴目標的後面。這樣做會使得Prolog有最多的機會不通過遞迴就找到答案。

 

Learn Prolog Now 翻譯 - 第三章 - 遞迴 - 第二節,規則順序,目標順序,終止

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.