Reputation: 2319
I am trying to write a Tail Recursive procedure to count the number of uninstantiated variables in a list. I am a little stuck, where am I going wrong.
My current query is below:
count([S,L],N) :- var(S), !, N+1.
count([L],N).
Upvotes: 1
Views: 2180
Reputation: 22585
Note: this answer presents a solution that is recursive but not tail recursive. For a tail recursive solution you should use an accumulator as can be shown in other answers from this question.
As with any recursive procedure, you should add a proper base case. In this case, it should be a clause with an empty list that returns unifies 0 with the number of uninstantiated variables:
count([], 0).
Check the clause you've written. It takes as input a list of two elements instead of a list represented as a Head item and a tail list, and it really does nothing with N:
count([Head|Tail], M):-
var(Head),
!,
count(Tail, N),
M is N+1.
And finally, you should also add a clause to deal with the case when the first item of the list is not an uninstantiated variable:
count([_|Tail], N):- count(Tail, N).
Upvotes: 2
Reputation: 9292
Here is a tail recursion for counting variables in a list. It uses the technique of accumulators:
count(L, N) :- count(L, 0, N). % L=list, N=count, 0=value of the sum accumulator S
count([], S, S) :- !. % the innermost call, the accumulator S (2nd arg) "copied" to final result (3rd arg)
count([H| T], S, N):- var(H), !, S1 is S+1, count(T, S1, N). % increase accumulator if H is var
count([H| T], S, N):- count(T, S, N). % keep accumulator if H is not var
No calls follow the last recursive calls in all clauses.
Upvotes: 2
Reputation: 20602
There is no recursion here, because in order to have recursion, you must define something in terms of itself - you'll notice an absence of the count/2
rule on the right hand side in your code.
% two paths, variable and non-variable
% and a base case to start the count
count([S|L], N) :- var(S), !, count(L, N0), N is N0+1.
count([S|L], N) :- nonvar(S), !, count(L, N).
count([], 0).
Alternatively, this can be done simply with findall/3
.
count_alt(L, N) :- findall(S, (member(S, L), var(S)), D), length(D, N).
Upvotes: 0