只要第一个参数是一个基本列表,该解决方案就可以工作。在其他一些情况下,它是不正确的:
?- count([E], a, 0).
false.
在这里我们问
长度为 1 的列表的元素必须如何E
看起来才能使列表包含 0 次出现a
?
事实上,这个问题有答案,比如E = b
or E = c
:
?- count([b],a,0).
true.
?- count([c],a,0).
true.
因此,Prolog 的回答是不完整的。它应该说,是的。但是怎么做?
count([], _, 0).
count([E|Es], F, N0) :-
count(Es, F, N1),
if_(E = F, D = 1, D = 0),
N0 is N1+D.
这使用if_/3
和(=)/3
。
?- length(Xs, I), count_dif(Xs, a, N).
Xs = [],
I = N, N = 0
; Xs = [a],
I = N, N = 1
; Xs = [_A],
I = 1,
N = 0,
dif(_A, a)
; Xs = [a, a],
I = N, N = 2
; Xs = [_A, a],
I = 2,
N = 1,
dif(_A, a) ;
Xs = [a, _A],
I = 2,
N = 1,
dif(_A, a) ;
Xs = [_A, _B],
I = 2,
N = 0,
dif(_A, a),
dif(_B, a)
...
为了进一步改进这一点,我们可能会使用library(clpfd)
SICStus、YAP 和 SWI 中提供的版本。
:- use_module(library(clpfd)).
count([], _, 0).
count([E|Es], F, N0) :-
N0 #>= 0,
if_(E = F, D = 1, D = 0),
N0 #= N1+D,
count(Es, F, N1).
现在甚至以下终止:
?- count([a,a|_], a, 1).
false.
?- N #< 2, count([a,a|_], a, N).
false.