Marina Popa
Marina Popa

Reputation: 95

Prolog - Check number of occurences doesn't work as expected

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

Answers (3)

repeat
repeat

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 , 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 !

Upvotes: 3

CapelliC
CapelliC

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

Noxeus
Noxeus

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

Related Questions