这是伟大的,你得到了它现在的工作,通过使用声明算术!
我对你获得的溶液,即一些小的补充意见:
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