I'm trying to create a rule that counts the number of occurrences of a certain element in a given list, what I've tried so far does not seem to work the way I expect:
The first argument here should be the list, the second one the element we are looking for, and the last one the number of occurrences:
%empty list should always return 0 occurences
count([],E,0) :- true.
%if our head is what we are looking for, count
count([E|T],E,N) :- count(T,E,N-1).
%otherwise, do not count
count([H|T],E,N) :- H \== E, count(T,E,N).
Here H
is the head and T
the tail of the given list.
The base case e.g. count([],1,N).
returns N = 0
as expected, but as soon as the list is non empty, we always get false.
:
?- count([1],1,N).
false.
?- count([1,2,1,3],1,N).
false.
Can anyone point out what I'm doing wrong?
It seems to work when replacing the second line with
count([E|T],E,N+1) :- count(T,E,N).
But I just cannot figure out why this is not equivalent to my first idea.
Then we get
?- count([1,2,1,3],1,N).
N = 0+1+1
which is correct.
The problem is that N+1
(or N-1
) isn't evaluated, as can be seen by your second (working) example.
% empty list has 0 occurrences
count([], _, 0).
% if our head is what we are looking for, count
count([E|T], E, N) :-
N_1 is N - 1, % this is the important one
count(T, E, N_1).
% otherwise, do not count
count([H|T], E, N) :-
H \== E,
count(T, E, N).
is
actually evaluates the equation, instead of unifying the N
in your next call with N-1
. That's why in your second example, you end up with N=0+1+1
instead of N=2
.