2016-09-17 155 views
1

我對Prolog相當陌生。無論如何,我試圖編寫一套遞歸規則,返回給定字符代碼列表中每個單詞的平均字符數。我的代碼如下。Prolog重新發起呼叫,並沒有明顯的原因失敗

medellangd(Text,AvgLen) :- 
    medellangd(Text,T,1,0,0), 
    AvgLen = T. 

medellangd([],AvgLen,Space,Words,Chars) :- 
    T is (Chars/Words), 
    AvgLen = T. 
medellangd([A|B],AvgLen,Space,Words,Chars) :- 
    succ(Chars,C), 
    updatewords(A,Space,Words,W), 
    updatespace(A,S), 
    medellangd(B,T,S,W,C), 
    AvgLen = T. 

updatewords(A,1,Words,W) :- 
    member(A, [65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122]) 
    -> succ(Words,S), 
     W = S 
    ; W = Words. 
updatewords(A,0,Words,W) :- 
     W = Words. 

updatespace(A,S) :- 
    member(A,[65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122]) 
    -> S = 0 
    ; S = 1. 

,其原因我也說不上來,雖然AvgLen得到正確的值,序言當我打電話medellangd([68,69],AvgLen)返回false。當我跟蹤這個調用時,儘管每次調用最初在AvgLen獲取其值之前退出,但如果在AvgLen值賦值之後輸入分號,並且失敗,則Prolog決定重做「(9)更新字(68,1,0,_G2574)」 。爲什麼會發生?

+0

我幾乎可以肯定,你的'updatewords/4'就是選擇點來自於。順便說一下,我不明白你爲什麼要在謂詞定義的末尾做所有這些顯式的統一...你有沒有理由? – 2016-09-17 20:47:10

回答

1

你的謂詞工作正常,爲了找到一個解決方案prolog嘗試一切可能的方式,所以在給出答案AvgLen = 2之後,我們可以找到更多可行的解決方案。當Prolog試圖找到一個解決方案時,它會建立一個證明樹,在那裏它保存所有可能的方法來證明目標,並逐一嘗試它們,直到找到所有正確的答案,並且沒有其他方法來證明目標已經離開。這是調用重做的原因,嘗試更多可能的解決方案。如果你想謂詞變成了確定性 您可以添加切(!):

medellangd(Text,AvgLen) :- 
    medellangd(Text,T,1,0,0), 
    AvgLen = T,!. 

,當發現第一個正確的答案,不會再進一步​​搜索這些將停止。

一個簡單的例子來了解如何工作序言是:如果你查詢simple_example(L)

simple_example([]). 
simple_example([_]). 

以上謂詞成功。其中L是空的或它有一個元素。 現在,如果您嘗試查詢simple_example([])。或simple_example([1])。在跟蹤你會看到:

[trace] ?- simple_example([1]). 
    Call: (7) simple_example([1]) ? creep 
    Exit: (7) simple_example([1]) ? creep 
true. 

在另一方面,如果你寫的同一個例子是不同的:

simple_example2(L):- L=[]. 
    simple_example2(L):- L=[_]. 

謂詞simple_example2顯然是相當於simple_example但是如果你查詢simple_example2([])。在跟蹤你會看到,因爲我們有[]在simple_example2同時匹配l在會嘗試這兩種,當然只有第一個將是正確的:

[trace] ?- simple_example2([1]). 
    Call: (7) simple_example2([1]) ? Unknown option (h for help) 
    Call: (7) simple_example2([1]) ? Unknown option (h for help) 
    Call: (7) simple_example2([1]) ? Unknown option (h for help) 
    Call: (7) simple_example2([1]) ? creep 
    Call: (8) [1]=[] ? creep 
    Fail: (8) [1]=[] ? creep 
    Redo: (7) simple_example2([1]) ? creep 
    Call: (8) [1]=[_G3328] ? creep 
    Exit: (8) [1]=[1] ? creep 
    Exit: (7) simple_example2([1]) ? creep 
true. 
+0

是否有可能在算法上確保在證明樹中只有一個Prolog路徑? –

+0

不,它不需要算法,但prolog如何理解是否有更多的解決方案。這是prolog搜索的主要特徵,我將更新答案以解釋prolog如何以一個非常簡單的例子作出選擇,但是在更復雜的程序中,確保prolog沒有其他選項是沒有意義的。 Againg如果你只想要一個解決方案,你可以使用剪切。 – coder

+0

你有什麼想法在我的情況下會導致失敗嗎? –