The cuts are indeed one problem: Try for example the most general query
?- count(Ls, L, C).
and see that it yields only a single solution, although there clearly should be infinitely many because the first argument can be a list of arbitrary length. So first remove all cuts. The other problem is (\=)/2
, which is not a true relation: It is only sound if its arguments are ground. Instead of (\=)/2
, use the more general predicate dif/2
, which is available in SWI-Prolog as well as other systems and constrains its arguments to be different terms. Your predicate will then work in all directions.
EDIT: I expand on the "usable in all directions" point. Consider the following version of list_term_count/3
, which relates a list to the number of occurrences of a term in that list, using clpfd constraints in addition to dif/2
:
list_term_count([], _, 0).
list_term_count([L|Ls], L, N) :-
list_term_count(Ls, L, N0),
N #= N0 + 1.
list_term_count([L|Ls], E, N) :-
dif(L, E),
list_term_count(Ls, E, N).
We can use it in the most general way imaginable, which is leaving all arguments unspecified, and obtain correct answers:
?- list_term_count(Ls, E, N).
Ls = [],
N = 0 ;
Ls = [E],
N = 1 .
To fairly enumerate all solutions, we can use length/2
:
?- length(Ls, _), list_term_count(Ls, E, N).
Ls = [],
N = 0 ;
Ls = [E],
N = 1 ;
Ls = [_G167],
N = 0,
dif(_G167, E) .
Notice the dif/2
constraint which occurs as a residual goal, and which constrains the list's element to be distinct from E
when N
is 0
. This is how we can express an infinite set of terms that is not restricted in any other way except for being different from E
.
Any other instantiation pattern is also admissible. For example:
?- list_term_count([a], E, N).
E = a,
N = 1 ;
N = 0,
dif(E, a).
Or for example:
?- list_term_count([X], a, N).
X = a,
N = 1 ;
N = 0,
dif(X, a).
This generality is one of the benefits of using pure monotonic predicates in your programs. Using pure goals also allows us to quite freely reorder them.
count/3
built into SWI Prolog. – luksan