2013-04-10 59 views
-1

我使用SWI Prolog的學習Prolog的一個大學考試,我對之間的下列問題的兩種不同解決方案的差異有些疑惑使用CUT中的一些問題:關於這段序言鍛鍊

定義條款計數(X,L,NumX)其中X是原子,L是 列表和NumX是出現的次數即X出現在L.

這是第一個解決方案:

count0(_,[],0). 

count0(A, [A|Tail], N) :- 
      count0(A,Tail,N1), % L'elemento cercato appare N1 volte nella sottolista 
       N is N1+1.  % N vale N1+1 

count0(A, [B|Tail], N) :- 
      A\=B,   % A è diverso da B 
     count0(A,Tail,N). % N è il numero di occorrenze di A nella sottolista 

這是第二個解決方案:

count1(_,[],0). 

count1(A, [A|Tail], N) :- !, 
         count1(A, Tail, N1), 
       N is N1+1. 

count1(A, [_|Tail], N) :- count1(A, Tail, N). 

我的問題是,我不理解它扮演的角色在第二版的CUT

我知道CUT防止回溯在CUT被放置的特定點。

該程序的第一個版本檢查A是否與第二條規則中的B不同(我需要這個?如果第一條規則失敗了,所以這意味着A不與該頭的頭部統一該列表的頭是從A處的元素)

第二個版本不執行此檢查在第二個規則,但把削減的第一條規則不同...

這可能取決於由事實上(在第二個版本中)如果我不阻止回溯,那麼:在此之後,如果我強制使用回溯,Prolog給我第一個(正確)迴應;碰巧使用第二條規則:

count1(A, [_|Tail], N) :- count1(A, Tail, N). 

採取了不同的分支在計算和該分支我沒有N是N + 1?

回答

1

第一個版本在第二個子句中留下選擇點,而第二個版本在它進入第二個子句時對該子句進行提交(與剪切)。

第一個版本需要明確檢查項目是因爲,在回溯從列表的頭部不同,第三子句,將忽略第二條款是否成功之前執行。

如果您使用簡單的輸入列表說明1元素跟蹤兩個過程,您可以親自看到它。

?- count0(a,[a], Count). 

你的程序將項目與列表的匹配,並執行遞歸的第一個版本。然而,如果需要,它將在那裏留下選擇的位置以查看其他替代方案。 然後遞歸因爲基本情況(空列表)而結束,並且您得到Count = 1的結果。

如果您現在要求prolog其他選擇,它仍然有該選擇點,所以它會嘗試thirc子句。如果你沒有明確地檢查A和B是否不同,它會遞歸地調用它自己(再次使用空列表)並返回Count = 0這是一個錯誤的答案!

現在,您的程序的第二個版本(使用剪切的那個版本)。當prolog用第一個項目輸入第二個子句時,它會提交切割,所以它不會離開選擇點。現在您進行遞歸併以Count = 1的正確結果結束。

如果你現在要求prolog其他選擇,它會說沒有什麼可以檢查。 由於削減的結果,沒有必要檢查A和B是否有所不同,因爲您確定它們會不同,否則第二個條款將提交併且第三個條款不會被測試。

+0

好吧,現在對我來說更加清楚......最後一個問題是:在程序的第二個版本中(使用剪切),規則的順序很重要,是對的嗎? – AndreaNobili 2013-04-11 16:29:17

+1

@AndreaNobili:是的,這很重要。如果你交換最後兩個子句,你會得到不正確的結果(也是正確的)。 – gusbro 2013-04-11 16:49:41