Reputation: 95
In Prolog: I have the following function that counts the occurences of a certain element in a list:
%count(L:list,E:int,N:int) (i,i,o)
count([],_,0).
count([H|T],E,C):-H == E,count(T,E,C1),C is C1+1.
count([_|T],E,C):-count(T,E,C).
I tested it and it works well. But here comes the problem, I have another function that has to check if "1" occurs less than 2 times in a list.
check(L):-count(L,1,C),C<2.
Whenever I try to check the list [1,1,1,1]
for example, the result I get is "true", which is wrong, and I have no idea why. I tried to make some changes, but the function just won't work.
Upvotes: 4
Views: 86
Reputation: 18726
Improve your testing habits!
When testing Prolog code don't only look at the first answer to some query and conclude "it works".
Non-determinism is central to Prolog.
Quite often, some code appears to be working correctly at first sight (when looking at the first answer) but exhibits problems (mainly wrong answers and/or non-termination) upon backtracking.
Coming back to your original question... If you want / need to preserve logical-purity, consider using the following minimal variation of the code @Ruben presented in his answer:
count([],_,0). count([E|T],E,C) :- count(T,E,C1), C is C1+1. count([H|T],E,C) :- dif(H,E), count(T,E,C).
dif/2
expresses syntactic term inequality in a logical sound way. For info on it look at prolog-dif!
Upvotes: 3
Reputation: 60024
second and third clauses heads match both the same sequence. As a minimal correction, I would commit the test
count([],_,0).
count([H|T],E,C):-H == E,!,count(T,E,C1),C is C1+1.
count([_|T],E,C):-count(T,E,C).
Upvotes: 0
Reputation: 577
It happens because count([1,1,1,1],1,1)
is also true! In your last count
it can also be matched when H does equal E. To illustrate this, use ;
to make prolog look for more answers to count([1,1,1,1],1,R)
. You'll see what happens.
count([],_,0).
count([E|T],E,C):-
count(T,E,C1),
C is C1+1.
count([H|T],E,C):-
H \= E,
count(T,E,C).
check(L) :-
count(L,1,C),
C < 2.
?- check([1,1,1,1,1]).
false
?- check([1]).
true
Upvotes: 1