通过使用声明性算术,您现在可以使用它了,真是太好了!
我对您获得的解决方案有一些额外的评论,即:
计数(_,[],0):-!。
计数(埃尔,[埃尔|T],N):-
计数(El,T,N1),
N #= N1 + 1。
计数(El,[Y|T],N):-
埃尔\= Y,
计数(El,T,N)。
检查(列表 1,列表 2):-
计数(3,列表1,M),
计数(2,列表2,N),
M#=N。
首先,请注意check/2
代码中没有使用它,因此我在下面省略了它的定义。
最一般的查询
当我查看我一无所知的 Prolog 代码时,我总是首先尝试最通用的查询,其中所有参数都是变量。理想情况下,答案向我展示了一般的解决方案。
例如,在您的情况下:
?- 计数(E,Ls,C)。
LS = [],
C = 0。
这——错误地——表明你的谓词只有一个解!这显然不是故意的。
因此,作为第一步,我建议您删除!/0
并将此代码更改为:
计数(_,[],0)。
计数(埃尔,[埃尔|T],N):-
计数(El,T,N1),
N #= N1 + 1。
计数(El,[Y|T],N):-
埃尔\= Y,
计数(El,T,N)。
应用此更改后,我们得到:
?- 计数(E,Ls,C)。
LS = [],
C = 0 ;
Ls = [E],
C = 1 ;
Ls = [E, E],
C = 2;
Ls = [E, E, E],
C = 3。
这看起来好多了:我们现在得到了几个有效的答案。
终止
这个谓词可能产生多少答案?特别是,是否只有有限多个答案?如果是这样,我们希望以下查询终止:
?- 计数(E,Ls,C),假。
您可以尝试一下,看看它实际上并没有终止(至少不会很快终止)。这是一个好兆头,因为从 的正确实现中count/3
,我们期望在最一般的情况下不会终止!
完整性
理想情况下,我们希望谓词是完整的:它不应该省略有效的答案。
例如:
?- 计数(E,[X,Y,Z],C)。
E = X,X = Y,Y = Z,
C = 3 ;
错误的。
这些真的都是解决方案吗?我不这么认为!当然有长度为 3 的列表不同于 [E,E,E]
.
而且,事实上,您的程序在某种意义上也“知道”它们:
?- 计数(E,[1,2,3],C)。
E = C,C = 1;
错误的。
但同样,这些肯定不是所有情况!与 1不同的答案在E
哪里?
您正面临这些问题,因为您使用的是非单调 (\=)/2
谓词。这有一些非常难以理解的属性,特别是如果您目前才刚刚开始学习 Prolog。例如:
?- X \= Y, XY = ab。
假的。
?- XY = ab, X \= Y。
X = 一个,
Y = b。
我建议使用dif/2
来表示两个术语是不同的,获得以下版本:
计数(_,[],0)。
计数(埃尔,[埃尔|T],N):-
计数(El,T,N1),
N #= N1 + 1。
计数(El,[Y|T],N):-
差异(El,Y),
计数(El,T,N)。
有了这个版本,我们得到:
?- 计数(E,[X,Y,Z],C)。
E = X,X = Y,Y = Z,
C = 3 ;
E = X,X = Y,
C = 2,
差异(Y,Z);
E = X,X = Z,
C = 2,
差异(Z,Y);
等等
而且,特别是:
?- 计数(E,[1,2,3],C)。
E = C,C = 1;
E = 2,
C = 1 ;
E = 3,
C = 1 ;
C = 0,
差异(E,3),
差异(E,2),
差异(E,1)。
这涵盖了所有可能出现的情况!
公平枚举
由于谓词是纯单调的,我们可以用它通过迭代深化来公平地列举答案。
例如:
?- 长度(Ls,_),计数(E,Ls,C)。
LS = [],
C = 0 ;
Ls = [E],
C = 1 ;
LS = [_G588],
C = 0,
差异(E,_G588);
Ls = [E, E],
C = 2;
Ls = [E, _G597],
C = 1,
差异(E,_G597)。
C = 2 ;
等等
这非常好,并且表明我们可以将其用作真正的关系,不仅用于计数,还用于生成。
因此,您可以考虑更恰当地描述该谓词的一般含义的谓词名称。我把它留作练习。
尾递归版本
请注意,由于您使用的是纯谓词,因此您可以自由地重新排序您的目标,并使您的谓词tail recursive产生:
计数(_,[],0)。
计数(埃尔,[埃尔|T],N):-
N #= N1 + 1,
计数(El,T,N1)。
计数(El,[Y|T],N):-
差异(El,Y),
计数(El,T,N)。
决定论
我们目前还有例如:
?- 计数(a,[a,a,a],Cs)。
Cs = 3 ;
假的。
使用if_/3
,您可以提高此谓词的确定性:
:- 使用模块(库(reif))。
计数(_,[],0)。
计数(E,[L|Ls],N):-
if_ (E=L, N #= N1 + 1, N #= N1),
计数(E,Ls,N1)。
这使您的谓词至少适合索引。在这种情况下是否提高确定性取决于 Prolog 系统的索引机制。