2013-11-21 34 views
3

我在序言編程初學者,我希望你謙虛,幫助我通過這種混亂總和在列表中的元素在序言中就不需要解釋

我現在面臨一個問題來計算序言之和我有答案,但我不清楚。 答案是:

list_sum([], 0). 
list_sum([Head | Tail], Total) :- 
    list_sum(Tail, Sum1), 
    Total = Head + Sum1. 

的是我不明白是什麼Sum1以及如何計劃將逐步

工作,它首先會檢查的首要條件list_sum([], 0).,而條件不符合它會將列表分爲2部分HeadTail然後呢?


我希望你接受一個初學者,並給他一些時間來糾正他的困惑。
謝謝你們

回答

4

這是一個經典的遞歸方法 - 你需要熟悉它才能理解Prolog。

您的規則有兩個條款 - 一個用於空列表,另一個用於非空列表。空列表子句表示空列表的元素總和爲零(這是完全合理的)。這被稱爲「遞歸的基本情況」。每個終止遞歸規則都必須有一個基本情況。

第二個條款稍微複雜一點。它大致是這樣說的:「要計算非空列表中的元素總和,首先切掉初始元素,然後計算出結果的較短列表中的元素總和,然後調用Sum1,現在通過加入Total來計算初始元素的值爲Sum1

第二個子句遞歸地將列表分解成一系列較短的列表,直到他們到達一個空列表爲止,此時第一個子句步入,提供。一個空列表

考慮這個例子:

list_sum([12, 34, 56], X) 
    list_sum([34, 56], <unknown-1>) 
     list_sum([56], <unknown-2>) 
      list_sum([], 0)   ---> succeeds with Total bound to 0 
     <unknown-2> becomes 0 + 56 ---> succeeds with Total bound to 56 
    <unknown-1> becomes 0 + 56 + 34 ---> succeeds with Total bound to 90 
X becomes 0 + 56 + 34 + 12   ---> succeeds with X bound to 102 

這是可行的,因爲遞歸鏈中的每個調用級別都獲得自己的變量Sum1。這些值開始無界限,但是一旦遞歸調用鏈「降到最低點」,Sum1就開始獲取按先前級別計算的值。最終,調用鏈達到頂層,將最終結果綁定到調用者傳遞的變量。

+0

非常感謝。非常感謝你 。上帝祝福你 。我很難理解這一點。但你對我所做的一切都很簡單 – user3018890

+0

好的解釋,但「用102返回」等等,有點讓人誤解,特別是對於曾經在程序上思考的人。 Prolog子句不返回值;他們根本不「返回」。比如說「成功地用X綁定到102」等等會更準確。 –

+0

@TedHopp我也想過這個 - 返回有點誤導。我添加了「with」,試圖暗示價值不是從程序意義上「返回」的。不過,我喜歡你的措辭比我的更好 - 感謝你的評論! – dasblinkenlight

5

程序中有一個小錯誤開始 - 行Total = Head + Sum意味着Total是一個結構+有兩個參數。您可能的意思是is,而不是=,意思是算術評估。但最好是用#=代替。

在你的問題你問什麼程序將做。在面向命令(「命令式」)的語言中,這是一個相當合理的問題,因爲您可以從程序中脫離出來的唯一含義就是它的分步操作。但是在Prolog中,情況有點不同。你仍然可以嘗試應用這種循序漸進的思維方式,但遲早你會意識到事情會變得非常複雜,這是因爲Prolog沒有一個控制流,而是兩個同時調用(AND-和OR-控制)。甚至「數據結構」也是不同的......

但是有一種方法可以讀取Prolog程序,它在命令式語言中沒有對應部分:您可以將程序理解爲參數之間的關係。通過這種方式,您可以專注於關係看起來像什麼,而不是程序方面。畢竟,如果描述的關係是錯誤的,那麼詢問程序如何做到這一點是毫無意義的。

因此,讓我改你的程序:

:- use_module(library(clpfd)). 
list_sum([], 0). 
list_sum([E|Es], S) :- 
    S #= E+T, 
    list_sum(Es, T). 

它首先將檢查的第一個條件list_sum([],0)。當條件不滿足時,會將列表分成H和T兩部分呢?

你的問題意味着有一個控制流(「雖然是這樣的典型構造暗示它」)。但它也可能以不同的方式工作。考慮查詢:

?- list_sum(Xs,0). 
Xs = [] ; 
Xs = [0] ; 
Xs = [_G1710, _G1713], 
_G1710+_G1713#=0 ... 

下面我們請什麼列出存在,其總和爲0。現在你的「同時」不再有意義。

我們得到的答案是:空白列表;與0的列表;一個兩元素列表,其中元素的總和爲0;等等......

瞭解這種方案的最佳方式是閱讀他們作爲像這樣的關係:

list_sum([], 0空列表具有總和0

的規則現在讀最好的箭頭:-即,從右到左的方向:

  • list_sum(Es, T).:*提供Es是總和T列表,並...

  • S #= E+T:... SET ...

  • :- ...那麼我們可以得出結論...

  • list_sum([E|Es], S)S是列表[E|Es]的總和。

以這種方式可以理解這些事情,而不必提及過程細節。還有更多的理解終止請參閱

+0

是的,我只是注意到這一點。感謝 – user3018890

+1

+1的解釋,我強烈推薦這種閱讀謂詞的方式,並使用有限域約束來進行整數運算。 – mat

相關問題