该解决方案只适用于第一个参数是一个确定列表的情况。在其他一些情况下,它是不正确的:
?- count([E], a, 0).
false.
这里我们要问的是:
如果一个列表的长度为1且其中不包含任何“a
”元素,那么这个列表中的元素E
应该长成什么样子?
实际上有许多可能的答案,比如E = b
或者 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.