Reputation: 61
I'm trying to count atoms in a list. I can count all the atoms but I can't count a specific atom. I know there's something wrong with my code but I'm not sure how to fix it.
This works to count all the atoms in a list (the E (element) is irrelevant here):
count_atoms(_,[],0).
count_atoms(E,[H|T],R):- number(H), count_atoms(E,T,R1),R is R1,!.
count_atoms(E,[H|T],R):- var(H), count_atoms(E,T,R1),R is R1,!.
count_atoms(E,[H|T],R):- atom(H), count_atoms(E,T,R1),R is R1+1,!.
But this doesn't work to find the E (element) in the list:
count_atoms(_,[],0).
count_atoms(E,[H|T],R):- number(H), count_atoms(E,T,R1),R is R1,!.
count_atoms(E,[H|T],R):- var(H), count_atoms(E,T,R1),R is R1,!.
count_atoms(E,[H|T],R):- atom(H), E==H, count_atoms(E,T,R1),R is R1+1,!.
The result I get each time is just false.
Does anyone know what I'm doing wrong?
Upvotes: 2
Views: 430
Reputation: 683
The question has already been answered by @DuDa - ypu forgot to take care of the case of a list member that is an atom different from whatever E is bound to. In addition, you didn't take care of the case that H is a structure.
I would only like to add that it makes things easier, if you do not try to enumerate all cases, but work with a catch-all clause, for expl:
count_atoms(_,[],0).
count_atoms(E,[E|T],R):- atom(E),count_atoms(E,T,R1),R is R1+1,!.
count_atoms(E,[_|T],R):- count_atoms(E,T,R). % catch-all
Even with the addition of the answer above, the proof of a question will still fail with lists that contain structures like [a,b,c,f(d),e]
, whereas it works with a catch-all clause.
For example, Prolog will answer the question ?- count_atoms(a,[a,b,c,f(d),e],R).
with no even with the addition above, but with R = 1.
when using a catch-all clause.
Upvotes: 1
Reputation: 5509
In SWI-Prolog, another possible solution is:
count_atoms(Atom, List, Count) :-
aggregate_all(count,
(member(Item, List),
atom(Item),
Item = Atom),
Count).
Here are some examples:
?- count_atoms(a, [a,b,a,X,c,f(d),a,Y,b,a], Count).
Count = 4.
?- count_atoms(b, [a,b,a,X,c,f(d),a,Y,b,a], Count).
Count = 2.
?- count_atoms(c, [a,b,a,X,c,f(d),a,Y,b,a], Count).
Count = 1.
?- count_atoms(d, [a,b,a,X,c,f(d),a,Y,b,a], Count).
Count = 0.
Upvotes: 0
Reputation: 3736
You did not state what happens if H
is an atom but not equal to E
.
Add this:
count_atoms(E,[H|T],R):- atom(H), E\==H, count_atoms(E,T,R),!.
Output:
?- count_atoms(a,[a,b,a,c],R).
R = 2.
Also there is a lot of improvement possible.
Upvotes: 1
Reputation: 878
An alternate approach:
count(H,List,Count):-
count1(H,List,0,Count).
count1(_, [], Count, Count). %base case
count1(H,[K|T],CountA,Count):- %Count atom in List
H=K,
CountB is CountA+1,
count1(H,T,CountB,Count).
count1(H,[K|T],CountA,Count):- %Don't count when atom not in list
H\=K,
count1(H,T,CountA,Count).
Example:
?- count(a,[a,a,a],Count).
Count = 3
false
?- count(b,[a,a,b,n,n,a],Count).
Count = 1
false
?- count(n,[a,a,b,n,n,a],Count).
Count = 2
false
?- count(c,[a,a,b,n,n,a],Count).
Count = 0
false
Upvotes: 0