2012-02-22 91 views
4

這是我的任務之一的問題:Prolog的分配

repCount(L, X, N)N在列表LX出現的次數是真實的。

這裏是我的代碼,我試圖解決遞歸問題:

repCount([], X, N) :- 
    N is 0. 
repCount([H|T], X, N) :- 
    count([H|T], X, N). 

count([], X, 0). 
count([H|T], X, N) :- 
    count(T, X, N1), 
    X =:= H, 
    N is N1 + 1. 

當我提供一個完整的相同號碼的名單像這樣它的工作原理:

?- repCount([2,2,2], 2, N). 
N = 3. 

但是,如果我提供具有至少一個不同值的列表:

?- repCount([2,2,22], 2, N). 
false. 

它返回false。我無法弄清楚爲什麼會發生這種情況,或者如何將其更改爲「跳過」不匹配的值,而不是將整個事件聲明爲false。任何輸入讚賞。

回答

4
count([H|T], X, N):- count(T, X, N1), X=:=H, N is N1 + 1. 

這裏你聲明如果X是H,N應該是N1 + 1;但是你沒有定義,如果X不是H(基本上缺少else子句) 這應該會發生什麼:

count([H|T], X, N):- 
    count(T, X, N1), 
    (X=:=H-> 
     N is N1 + 1 
     ; N is N1). 

另一種方法是:

count([H|T], X, N):- count(T, X, N1), X=:=H, N is N1 + 1. 

count([H|T], X, N):- X=\=H, count(T, X, N1), N is N1. 

但這是因爲計數效率低下(T,X,N-1)將被調用兩次,如果X不是H.我們可以通過在子句的頭部做了檢查解決這個問題:

count([H|T], H, N):- count(T, X, N1), N is N1 + 1. 

count([H|T], X, N):- count(T, X, N1), N is N1. 

或者乾脆: 計數([H | T],H,N): - 計數(T,X,N1),N是N1 + 1

count([H|T], X, N1):- X=\=H, count(T, X, N1). 
+0

非常感謝,謝謝。 – 2012-02-22 20:04:45

+0

你應該點擊upvote而不是說「謝謝」,而不用提高幫助你的人! – 2012-02-22 20:46:17

+1

目前太缺乏代表性,但只要我有足夠的空間,我們就會做。謝謝你的提示! – 2012-02-22 21:36:52

0

幾乎那裏......你需要使用一個累加器 ,因此:

repCount(Xs,Y,N) :- 
    count(Xs,Y,0,N) % the 3rd argument is the accumulator for the count, which we seed as 0 
    . 

count([],_,N,N).  % if the list is empty, unify the accumulator with the result 
count([X|Xs],Y,T,N) :- % if the list is non-empty, 
    X == Y ,    % and the head of the list (X) is the the desired value (Y), 
    T1 is T+1 ,   % then increment the count, and 
    count(Xs,Y,T1,N)  % recurse down, passing the incremented accumulator 
    .     % 
count([X|Xs],Y,T,N) :- % if the list is non-empty, 
    X \== Y ,   % and the head of the list(X) is not the desired value (Y), 
    count(Xs,Y,T,N)  % simply recurse down 
    .     % 
0

最初的問題沒有說明是否存在可以使用哪些謂詞的約束條件。

如果您被允許'欺騙'即ie。使用高階謂詞一樣,遞歸你Vs的你「的findall」自己做遞歸,這可以在一個單一的謂詞來完成:

repCount(L, X, N) :- 
    findall(X, member(X, L), ListOfX), 
    length(ListOfX, N). 
1

不過,假設你不準「欺騙」,如果你想使用遞歸,你不需要做「==」比較..你可以使用的Prolog的變量統一以達到同樣的目的:

% Job done all instances 
repCount2([], _, 0). 

% Head unifies with X/2nd parameter - ie X found 
repCount2([H|T], H, N) :- 
    repCount2(T, H, NewN), 
    N is NewN + 1. 

% We got here, so X not found, recurse around 
repCount2([_|T], X, N) :- 
    repCount2(T, X, N). 

在第二個謂語,H被提及兩次,這意味着如果列表的頭部與X相同,則遞減,然後將1遞增到遞歸的其餘部分的結果(其結束時加上0--基本情況,這就是accumul ator建成)。

+0

是的,但是......如果你打算這麼做的話,你需要在第二個子句中削減('!')來消除回溯時的選擇點,以免你得到多個結果。此外,如果搜索條件未綁定或列表包含未綁定項目,統一可能會產生...意外的結果。 – 2012-02-22 22:42:29

+0

尼古拉斯 - 謝謝。 – magus 2012-02-22 22:54:10

+1

@magus:在沒有'!/ 0'的最後一個句子中,最好使用dif/2。 '!/ 0'使你的程序不必要的不​​純。 – false 2012-02-22 23:04:45

2

一個有趣的也許除了什麼@magus寫道:如果你只關心元素,而不是元素本身的數量,你可以使用的findall/3這樣的:

list_elem_num(Ls, E, N) :- 
    findall(., member(E, Ls), Ds), 
    length(Ds, N). 
2

保留 - 附一從 tcount/3(=)/3幾乎沒有幫助!

目標tcount(=(X),Es,N)顯示「列表Es中有N個項目等於X」。

樣品查詢:

 
?- tcount(=(X), [a,b,c,a,b,c,a,b,a], N). 
( N = 4,  X=a 
; N = 3,    X=b 
; N = 2,       X=c 
; N = 0, dif(X,a), dif(X,b), dif(X,c) 
).          % terminates universally