這是偉大的,你得到了它現在的工作,通過使用聲明算術!
我對你獲得的溶液,即一些小的補充意見:
count(_, [], 0) :- !.
count(El, [El|T], N) :-
count(El, T, N1),
N #= N1 + 1.
count(El, [Y|T], N) :-
El \= Y,
count(El, T, N).
check(List1, List2) :-
count(3, List1, M),
count(2, List2, N),
M #= N.
首先,請注意check/2
在代碼中使用無門,所以我忽略它的定義如下。
最一般的查詢
當我回顧Prolog的代碼,我一無所知,我總是嘗試最一般的查詢首先,所有的參數都是變量。理想情況下,答案告訴我什麼解決方案看起來像一般。
例如,你的情況:
?- count(E, Ls, C).
Ls = [],
C = 0.
這—錯誤—表明,只有一個單一的解決的謂語!這顯然不是有意的。
因此,作爲第一步,我建議你刪除!/0
這個代碼更改爲:
count(_, [], 0).
count(El, [El|T], N) :-
count(El, T, N1),
N #= N1 + 1.
count(El, [Y|T], N) :-
El \= Y,
count(El, T, N).
隨着這一變化應用,我們得到:
?- count(E, Ls, C).
Ls = [],
C = 0 ;
Ls = [E],
C = 1 ;
Ls = [E, E],
C = 2 ;
Ls = [E, E, E],
C = 3 .
這看起來多少更好:我們現在得到幾個有效答案。
終止
多少答案可能這個謂詞的收益呢?特別是,只有有限很多答案?如果是的話,我們希望下面的查詢終止:
?- count(E, Ls, C), false.
你可以嘗試一下,看看它實際上不結束(至少不是很快)。這是一個好的跡象,因爲從正確執行count/3
,我們期待非終止在最一般的情況下!
完整性
理想情況下,我們希望謂詞是完整:它不應該省略有效的答案。
例如:
?- count(E, [X,Y,Z], C).
E = X, X = Y, Y = Z,
C = 3;
false.
難道這些真的所有解決方案?我不這麼認爲!當然,有不同於 [E,E,E]
的長度爲 3的列表。
而且,事實上,你的程序也「知道」他們在某種意義上:
?- count(E, [1,2,3], C).
E = C, C = 1 ;
false.
但同樣,這些肯定不是所有情況下! E
是不同 from 1的答案在哪裏?
您正面臨這些問題,因爲您使用的是非單調的(\=)/2
謂詞。這有幾個很難理解的屬性,特別是如果你目前只開始學習 Prolog。例如:
?- X \= Y, X-Y = a-b.
false.
?- X-Y = a-b, X \= Y.
X = a,
Y = b.
我建議使用dif/2
,而不是來表示兩個術語不同,獲得以下版本:
count(_, [], 0).
count(El, [El|T], N) :-
count(El, T, N1),
N #= N1 + 1.
count(El, [Y|T], N) :-
dif(El, Y),
count(El, T, N).
威特這個版本中,我們得到:
?- count(E, [X,Y,Z], C).
E = X, X = Y, Y = Z,
C = 3 ;
E = X, X = Y,
C = 2,
dif(Y, Z) ;
E = X, X = Z,
C = 2,
dif(Z, Y);
etc.
而且,特別是:
?- count(E, [1,2,3], C).
E = C, C = 1 ;
E = 2,
C = 1 ;
E = 3,
C = 1 ;
C = 0,
dif(E, 3),
dif(E, 2),
dif(E, 1).
這包括所有情況下可能出現!
博覽會枚舉
因爲該謂詞純和單調,我們可以用它來由迭代深化相當枚舉答案。
例如:
?- length(Ls, _), count(E, Ls, C).
Ls = [],
C = 0 ;
Ls = [E],
C = 1 ;
Ls = [_G588],
C = 0,
dif(E, _G588) ;
Ls = [E, E],
C = 2 ;
Ls = [E, _G597],
C = 1,
dif(E, _G597) .
C = 2;
etc.
這是相當不錯的,並表明我們可以用這個作爲一個真正的關係,不僅爲計數,同時也爲產生。
因此,你可以考慮謂詞名更恰當地描述了這個謂詞意味着在 一般。我把這留作練習。
尾遞歸版本
注意,因爲你正在使用純謂詞,您可以自由重新排序自己的目標,並讓你的謂語尾遞歸,得到以下特性:
count(_, [], 0).
count(El, [El|T], N) :-
N #= N1 + 1,
count(El, T, N1).
count(El, [Y|T], N) :-
dif(El, Y),
count(El, T, N).
確定性
我們目前仍然有例如:
?- count(a, [a,a,a], Cs).
Cs = 3 ;
false.
使用if_/3
,可以提高該謂詞的決定:
:- use_module(library(reif)).
count(_, [], 0).
count(E, [L|Ls], N) :-
if_(E=L, N #= N1 + 1, N #= N1),
count(E, Ls, N1).
這使你的斷言至少適合建立索引。在這種情況下是否改進確定性取決於您的Prolog系統的索引機制。
請參閱[本](http://stackoverflow.com/a/28971616/772868)以獲得純粹而高效的解決方案。 – false
您至少需要'dif(E1,Y)'代替'E1 \ = Y', – false