2016-11-17 82 views
1

的序言數數我學習序言,我想指望在一個列表中的特定元素occurence。元素錯誤

所以這裏是代碼 -

count(_, [], _) := !. 

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

count(El, [_|T], N) :- 
    count(El, T, N). 

check(List1, List2) :- 
    count(3, List1, M), 
    count(2, List2, N), 
    M is N. 

所以基本上我想傳遞給控制檯檢查([3,4,3],[2,3,4,5,2]),以及它應該返回true,因爲list1中3的出現次數與list2中出現次數2相同。而是它拋出我 -

Arguments are not sufficiently instantiated. 
Exception: (10) _G1383 is _L155+1 ? creep 
Exception: (9) count(3, [3, 4, 2], _G1385) ? creep 
Exception: (8) count(3, [2, 3, 4, 2], _G1385) ? creep 
Exception: (7) check([2, 3, 4, 2], [2, 3, 4]) ? creep 

什麼是這個原因,我該怎麼解決呢?我檢查了所有的論壇,並在任何地方寫入這個應該工作。這是一些與版本相關的東西,還是真的我在這裏錯過了一些東西?

編輯:使用SWI-Prolog的。編號2:

明白了,謝謝!

代碼:被稱爲

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. 
+1

請參閱[本](http://stackoverflow.com/a/28971616/772868)以獲得純粹而高效的解決方案。 – false

+1

您至少需要'dif(E1,Y)'代替'E1 \ = Y', – false

回答

1

您正在使用謂詞moded,因爲它們只能在非常特殊的情況下使用。特別是,(is)/2不能用作關係,因爲您在這裏需要它。

解決此問題的一種方法是使用更一般的謂詞來代替。例如,推理,當超過整數,可以考慮使用在各個方向的Prolog的系統CLP(FD)的約束,它的工作。

例如,GNU Prolog的,可以使錯誤消失,如果你只是通過(#=)/2更換(is)/2

 
count(_, [], _). 

count(El, [El|T], N) :- 
    N1 #= N + 1, 
    count(El, T, N1). 

count(El, [_|T], N) :- 
    count(El, T, N). 

check(List1, List2) :- 
    count(3, List1, M), 
    count(2, List2, N), 
    M #= N. 

現在,我們得到:

 
?- count(3, [3, 4, 2], C). 
C+1#=_1204 ; 
true ; 
false. 

(或根據在你的Prolog系統上,等價的答案)。

爲什麼?很明顯,該計劃有點不妥。

我離開發現的錯誤作爲一個練習。提示:M #= N看起來很可疑:這是真的當且僅當M等於 到   N ...

+0

我想SWI-prolog中的#=計爲註釋,需要檢查它。編輯更新的答案,我正在使用的prolog。 – user980952

+1

在SICStus Prolog,YAP和SWI中,您需要在開始處添加': - use_module(庫(clpfd))。'以使用聲明性整數算術。 – mat

2

這是偉大的,你得到了它現在的工作,通過使用聲明算術!

我對你獲得的溶液,即一些小的補充意見:

 
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系統的索引機制。