Prolog Ending a Recursion - prolog

countdown(0, Y).
countdown(X, Y):-
append(Y, X, Y),
Y is Y-1,
countdown(X, Y).
So for this program i am trying to make a countdown program which will take Y a number and count down from say 3 to 0 while adding each number to a list so countdown(3, Y). should produce the result Y=[3,2,1]. I can't seem the end the recursion when i run this and i was wondering if anyone could help me?
I cant seem to get this code to work any help? I seem to be getting out of global stack so I dont understand how to end the recursion.

Your original code
countdown( 0 , Y ) .
countdown( X , Y ) :-
append(Y, X, Y),
Y is Y-1,
countdown(X, Y).
has some problems:
countdown(0,Y). doesn't unify Y with anything.
Y is Y-1 is trying to unify Y with the value of Y-1. In Prolog, variables, once bound to a value, cease to be variable: they become that with which they were unified. So if Y was a numeric value, Y is Y-1 would fail. If Y were a variable, depending on your Prolog implementation, it would either fail or throw an error.
You're never working with lists. You are expecting append(Y,X,Y) to magically produce a list.
A common Prolog idiom is to build lists as you recurse along. The tail of the list is passed along on each recursion and the list itself is incomplete. A complete list is one in which the last item is the atom [], denoting the empty list. While building a list this way, the last item is always a variable and the list won't be complete until the recursion succeeds. So, the simple solution is just to build the list as you recurse down:
countdown( 0 , [] ) . % The special case.
countdown( N , [N|Ns] ) :- % The general case: to count down from N...
N > 0 , % - N must be greater than 0.
N1 is N-1 , % - decrement N
countdown(N1,Ns) % - recurse down, with the original N prepended to the [incomplete] result list.
. % Easy!
You might note that this will succeed for countdown(0,L), producing L = []. You could fix it by changing up the rules a we bit. The special (terminating) case is a little different and the general case enforces a lower bound of N > 1 instead of N > 0.
countdown( 1 , [1] ) .
countdown( N , [N|Ns] ) :-
N > 1 ,
N1 is N-1 ,
countdown(N1,Ns)
.
If you really wanted to use append/3, you could. It introduces another common Prolog idiom: the concept of a helper predicate that carries state and does all the work. It is common for the helper predicate to have the same name as the "public" predicate, with a higher arity. Something like this:
countdown(N,L) :- % to count down from N to 1...
N > 0 , % - N must first be greater than 0,
countdown(N,[],L) % - then, we just invoke the helper with its accumulator seeded as the empty list
. % Easy!
Here, countdown/2 is our "public predicate. It calls countdown/3 to do the work. The additional argument carries the required state. That helper will look like something like this:
countdown( 0 , L , L ) . % once the countdown is complete, unify the accumulator with the result list
countdown( N , T , L ) . % otherwise...
N > 0 , % - if N is greater than 0
N1 is N-1 , % - decrement N
append(T,[N],T1) , % - append N to the accumulator (note that append/3 requires lists)
countdown(N1,T1,L) % - and recurse down.
. %
You might notice that using append/3 like this means that it iterates over the accumulator on each invocation, thus giving you O(N2) performance rather than the desired O(N) performance.
One way to avoid this is to just build the list in reverse order and reverse that at the very end. This requires just a single extra pass over the list, meaning you get O(2N) performance rather than O(N2) performance. That gives you this helper:
countdown( 0 , T , L ) :- % once the countdown is complete,
reverse(T,L) % reverse the accumulator and unify it with the result list
. %
countdown( N , T , L ) :- % otherwise...
N > 0 , % - if N is greater than 0
N1 is N-1 , % - decrement N
append(T,[N],T1) , % - append N to the accumulator (note that append/3 requires lists)
countdown(N1,T1,L) % - and recurse down.
. %

There are several errors in your code:
first clause does not unify Y.
second clause uses append with first and third argument Y, which would only succeed if X=[].
in that clause you are trying to unify Y with another value which will always fail.
Y should be a list (according to your comment) in the head but you are using it to unify an integer.
You might do it this way:
countdown(X, L):-
findall(Y, between(1, X, Y), R),
reverse(R, L).
between/3 will give you every number from 1 to X (backtracking). Therefore findall/3 can collect all the numbers. This will give you ascending order so we reverse/2 it to get the descending order.
If you want to code yourself recursively:
countdown(X, [X|Z]):-
X > 1,
Y is X-1,
countdown(Y, Z).
countdown(1, [1]).
Base case (clause 2) states that number 1 yields a list with item 1.
Recursive clause (first clause) states that if X is greater than 1 then the output list should contain X appended with the result from the recursive call.

Related

Is there any way to check whether input n is less than or equal to length of list?

I am new to prolog, I wish to get a function:
drop(N, X, Y) that prints list Y which is the list X with its Nth element removed. If X does not have an Nth element then the predicate should fail.
Example:
1)drop(2,[1,2,3,4,5,6],Y) should give Y=[1,3,4,5,6].
2)drop(8,[1,2,3,4,5,6],Y) should fail.
I tried to get a function that appends an element of X to Y if it is not an Nth element and skips the element if it is an Nth element. Please see the following code:
drop(N,X,Y) :- integer(N),N>0,drop(X,1,N,Y).
drop([], _ , _ , [] ) .
drop( [X1|X] , P , N , [X1|Y] ) :- N=\=P , P1 is P+1 , drop(X,P1,N,Y) .
drop( [_|X] , P , N ,Y) :- N =:= P , P1 is P+1 , drop(X,P1,N,Y) .
The problem arises if N is greater than the length of the list, my code will print the entire list, but the function is supposed to fail in this case. I am not able to find a way to compare N with the length of the list since every function in prolog returns a binary value(according to my knowledge).
Any help will be much appreciated!
You are quite close. There are two things that you should change here:
once we have reached the correct index, we should no longer recurse on drop but just return the rest of the list; and
you should remove the drop([], _, _, []) line, since given we dropped an element, we will no longer recurse (see previous point).
Note that we can each time decrement the value for N and thus prevent using two variables. Like:
drop(N, X, Y) :-
integer(N),
drop_(N, X, Y).
drop_(1, [_|T], T).
drop_(N, [X|T], [X|T2]) :-
N > 1,
N1 is N-1,
drop_(N1, T, T2).

Prolog Picking from a list and Summing specific Values

sumPicker([[]|_], Y, Z).
sumPicker([X|X1], Y, Z):-
downList(Y, X, Sum),
Total is Z,
Z is Total + Sum,
sumPicker(X1,Y, Z).
downList([Z|_], 1, Z).
downList([_|B],Count, Number):- Count > 1,
SendCount is Count - 1,
downList(B, SendCount, Number).
So this code is basically suppose to take in Two lists sumPicker([3,5], [1,2,3,4,5,6], X). The program then takes the first list and depending on the value of the number, so in this case 3, it will find the third number in the second list then it will find the 5th number of the second list and add them together.
ERROR: is/2: Arguments are not sufficiently instantiated is what i am getting
I'm assuming that your instructor would like you to work out the recursion yourself, rather than using built-in list operations. To that end, you could approach it something like this, using no built-ins at all.
A common prolog idiom is to have a simple "public" predicate that invokes a "helper" predicate that carries state (in this case, the current position in the list and the running sum). Often, that "helper" predicate will have the same functor (name) as the public predicate, with a higher arity (number of arguments).
So, first we have the public predicate, sum_of_desired/3:
sum_of_desired( Indices , Numbers , Sum ) :- % to sum certain list elements,
sum_of_desired( Indices , Numbers , 0 , Sum ) - % invoke the helper
. %
All it does is invoke the helper, sum_of_desired/4. This helper predicate carries an extra argument that is its state: an accumulator that contains the running sum. When it succeeds, that running sum is unified with the final total. This is because, in Prolog, you can't change the value of a variable: once you assign a value to a variable, it ceases to be variable. It become that with which it was unified (that's it's called unification). The only way to undo that assignment is via backtracking.
Typically, a recursive problem has a few special cases and a more general case. So, here, our helper predicate has 2 clauses:
The first clause is the special case: the list of desired indices is empty, in which case the finally sum is the current value of the accumulator (0 initially).
the second clause is the recursive general case: here we find the desired list item, add it to the running total and recurse down, moving on to the next item in the list of desired list items.
sum_of_desired( [] , _ , S , S ) . % the list of desired indices is empty: unify the accumulator with the result.
sum_of_desired( [I|Is] , L , T , S ) :- % otherwise...
get_nth_item(I,L,N) , % - get the nth item from the list
T1 is T+N , % - add it to the running total
sum_of_desired(Is,T1,S) % - and recurse down
. %
Finally, this predicate, get_nth_item/3, simple recursively walks the list, looking for the nth item in the list, where n is relative to 1 (e.g., the first item in the list is at index 1). When it finds it, it's returned as the 3rd argument of the predicate.
Again, here you will note that we have a single terminating special case and the more general recursive special case:
get_nth_item( 1 , [X|_] , X ) . % found it!
get_nth_item( N , [_|Xs] , R ) :- % otherwise...
N > 1 , % - if N > 1 ,
N1 is N-1 , % - decrement N
nth_item( N1 , Xs , R ) % - recurse down.
. % - easy!

Is there anybody to explain how does this code actually work?(PROLOG)

So, the story began with counting the number of elements inside a list.
Then, I encountered this code when I searched for the solutions in Internet.
count([],0).
count([_HEAD|TAIL],X) :-
count(TAIL,X1),
X is X1+1.
However, there was no clear explanation on how the code actually worked and that is why I ask here in order to get a clear explanation about this code.
Hope that someone can explain step by step so that I can understand better.
Please think declaratively. You are relating a list to its length, so a better, relational name would be list_length/2: The first argument is a list, the second its length.
Obviously, the length of the empty list [] is 0.
Further, if Tail is a list of length L0, then the length of [_|Tail] is the number L0 + 1.
count([] ,0) means that an empty list has 0 element.
Now, to count the elements of a list
count([_HEAD|TAIL],X):-
% we remove the first element of the list
% we count the elements of the rest of the list
count(TAIL,X1),
% and we add 1 to the number of the elements of the rest
X is X1+1.
Learning to think recursively is hard. Most recursive problems can be broken down into a few "special cases" and the general case. In this case, we have two cases:
the empty list. This is our special case. The length of the empty list is ALWAYS zero.
A non-empty list. This is our general case.We have the list's head (a single item) and its tail (the remainder of the list: zero or more items). So, we can say that the length of a non-empty list is the length of its tail, plus 1 (the head).
Prolog lets you simply declare these to be facts defining truth. Then we let the Prolog inference engine determine the truth or falsity of an assertion. To whit:
count( [] , 0 ) . % The count of an empty list is zero
count( [_|Xs] , N ) :- % If the list is non-empty,
count( Xs, T ) , % - we count its tail as T
N is T+1 % - and then add 1.
. %
Then... you can say things like:
?- count([],3).
false.
?- count([a,b,c],3).
true.
This also works in a generative manner:
?- count( List , 3 ) .
List = [_G938, _G941, _G944] .
Or even...
?- count(X,N).
X = [], N = 0 ;
X = [_G950], N = 1 ;
X = [_G950, _G953], N = 2 ;
X = [_G950, _G953, _G956], N = 3 ;
...
Note that this is not tail-recursive and feed a list of sufficient length, will eventually overflow its stack.
You can write it in a tail-recursive manner as well, which might be easier to understand:
count( Xs , N ) :- % to count the number of items in a list,
count( Xs , 0 , N ) % - invoke the helper, seeding the accumulator with 0.
. %
count( [] , N , N ) . % if the source list is empty, the accumulator contains the number of items in the list.
count( [_|Xs] , T , N ) :- % otherwise (source list is non-empty)
T1 is T+1 , % - increment the accumulator, and
count(Xs,T1,N) % - recurse down on the tail, passing the incremented accumulator
. %

Sum of the first n numbers in prolog

Hello can anyone help me compute the sum of the first n numbers. For example n=4 => sum = 10.
So far I've wrote this
predicates
sum(integer,integer)
clauses
sum(0,0).
sum(N,R):-
N1=N-1,
sum(N1,R1),
R=R1+N.
This one works but I need another implementation. I don't have any ideas how I could make this differen . Please help
What #mbratch said.
What you're computing is a triangular number. If your homework is about triangular numbers and not about learning recursive thinking, you can simply compute it thus:
triangular_number(N,R) :- R is N * (N+1) / 2 .
If, as is more likely, you're learning recursive thought, try this:
sum(N,R) :- % to compute the triangular number n,
sum(N,1,0,R) % - invoke the worker predicate with its counter and accumulator properly seeded
.
sum(0,_,R,R). % when the count gets decremented to zero, we're done. Unify the accumulator with the result.
sum(C,X,T,R) :- % otherwise,
C > 0 , % - assuming the count is greater than zero
T1 is T+X , % - increment the accumulator
X1 is X+1 , % - increment the current number
C1 is C-1 , % - decrement the count
sum(C1,X1,T1,R) % - recurse down
. % Easy!
Edited to add:
Or, if you prefer a count down approach:
sum(N,R) :- sum(N,0,R).
sum(0,R,R). % when the count gets decremented to zero, we're done. Unify the accumulator with the result.
sum(N,T,R) :- % otherwise,
N > 0 , % - assuming the count is greater than zero
T1 is T+N , % - increment the accumulator
N1 is N-1 , % - decrement the count
sum(N1,T1,R) % - recurse down
. % Easy!
Both of these are tail-recursive, meaning that the prolog compiler can turn them into iteration (google "tail recursion optimization" for details).
If you want to eliminate the accumulator, you need to do something like this:
sum(0,0).
sum(N,R) :-
N > 0 ,
N1 is N-1 ,
sum(N1,R1) ,
R is R1+N
.
A little bit simpler, but each recursion consumes another stack frame: given a sufficiently large value for N, execution will fail with a stack overflow.
sum(N, Sum) :-
Sum is (N + 1) * N / 2 .
Since you already got plenty of advice about your code, let me throw in a snippet (a bit off-topic).
Counting, and more generally, aggregating, it's an area where Prolog doesn't shine when compared to other relational,declarative languages (read SQL). But some vendor specific library make it much more pleasant:
?- aggregate(sum(N),between(1,4,N),S).
S = 10.
This is the "heart" of your program:
sum(N,R):-
R=R+N,
N=N-1,
sum(N,R).
The =/2 predicate (note the /2 means it accepts 2 arguments) is the instantiation predicate, not an assignment, or logical equal. It attempts to unify its arguments to make them the same. So if N is anything but 0, then R=R+N will always fail because R can never be the same as R+N. Likewise for N=N-1: it will always fail because N and N-1 can never be the same.
In the case of =/2 (unification), expressions are not evaluated. They are just terms. So if Y = 1, then X = Y + 1 unifies X with 1+1 as a term (equivalently written +(1,1)).
Because of the above issues, sum will always fail.
Numerical assignment of an arithmetic expression is done in Prolog with the is/2 predicate. Like this:
X is Y + 1.
This operator unifies the value of X to be the same as the value of the evaluated expression Y+1. In this case, you also cannot have X is X+1 for the same reason given above: X cannot be made the same as X+1 and Prolog does not allow "re-instantiation" of a variable inside of a clause. So you would need something like, X1 is X + 1. Also note that for is/2 to work, everything in the expression on the right must be previously instantiated. If any variables in the expression on the right do not have a value, you will get an instantiation error or, in the case of Turbo Prolog, Free variable in expression....
So you need to use different variables for expression results, and organize the code so that, if using is/2, variables in the expression are instantiated.
EDIT
I understand from Sergey Dymchenko that Turbo Prolog, unlike GNU or SWI, evaluates expressions for =/2. So the = will work in the given problem. However, the error regarding instantiation (or "free variable") is still caused by the same issue I mentioned above.
sum(N, N, N).
sum(M, N, S):-
N>M,
X is M+1,
sum(X, N, T),
S is M+T.
?- sum(1,5,N).
N = 15 .

Prolog - sequence in list

We want to build a predicate that gets a list L and a number N and is true if N is the length of the longest sequence of list L.
For example:
?- ls([1,2,2,4,4,4,2,3,2],3).
true.
?- ls([1,2,3,2,3,2,1,7,8],3).
false.
For this I built -
head([X|S],X). % head of the list
ls([H|T],N) :- head(T,X),H=X, NN is N-1 , ls(T,NN) . % if the head equal to his following
ls(_,0) :- !. % get seq in length N
ls([H|T],N) :- head(T,X) , not(H=X) ,ls(T,N). % if the head doesn't equal to his following
The concept is simply - check if the head equal to his following , if so , continue with the tail and decrement the N .
I checked my code and it works well (ignore cases which N = 1) -
ls([1,2,2,4,4,4,2,3,2],3).
true ;
false .
But the true answer isn't finite and there is more answer after that , how could I make it to return finite answer ?
Prolog-wise, you have a few problems. One is that your predicate only works when both arguments are instantiated, which is disappointing to Prolog. Another is your style—head/2 doesn't really add anything over [H|T]. I also think this algorithm is fundamentally flawed. I don't think you can be sure that no sequence of longer length exists in the tail of the list without retaining an unchanged copy of the guessed length. In other words, the second thing #Zakum points out, I don't think there will be a simple solution for it.
This is how I would have approached the problem. First a helper predicate for getting the maximum of two values:
max(X, Y, X) :- X >= Y.
max(X, Y, Y) :- Y > X.
Now most of the work sequence_length/2 does is delegated to a loop, except for the base case of the empty list:
sequence_length([], 0).
sequence_length([X|Xs], Length) :-
once(sequence_length_loop(X, Xs, 1, Length)).
The call to once/1 ensures we only get one answer. This will prevent the predicate from usefully generating lists with sequences while also making the predicate deterministic, which is something you desired. (It has the same effect as a nicely placed cut).
Loop's base case: copy the accumulator to the output parameter:
sequence_length_loop(_, [], Length, Length).
Inductive case #1: we have another copy of the same value. Increment the accumulator and recur.
sequence_length_loop(X, [X|Xs], Acc, Length) :-
succ(Acc, Acc1),
sequence_length_loop(X, Xs, Acc1, Length).
Inductive case #2: we have a different value. Calculate the sequence length of the remainder of the list; if it is larger than our accumulator, use that; otherwise, use the accumulator.
sequence_length_loop(X, [Y|Xs], Acc, Length) :-
X \= Y,
sequence_length([Y|Xs], LengthRemaining),
max(Acc, LengthRemaining, Length).
This is how I would approach this problem. I don't know if it will be useful for you or not, but I hope you can glean something from it.
How about adding a break to the last rule?
head([X|S],X). % head of the list
ls([H|T],N) :- head(T,X),H=X, NN is N-1 , ls(T,NN) . % if the head equal to his following
ls(_,0) :- !. % get seq in length N
ls([H|T],N) :- head(T,X) , not(H=X) ,ls(T,N),!. % if the head doesn't equal to his following
Works for me, though I'm no Prolog expert.
//EDIT: btw. try
14 ?- ls([1,2,2,4,4,4,2,3,2],2).
true ;
false.
Looks false to me, there is no check whether N is the longest sequence. Or did I get the requirements wrong?
Your code is checking if there is in list at least a sequence of elements of specified length. You need more arguments to keep the state of the search while visiting the list:
ls([E|Es], L) :- ls(E, 1, Es, L).
ls(X, N, [Y|Ys], L) :-
( X = Y
-> M is N+1,
ls(X, M, Ys, L)
; ls(Y, 1, Ys, M),
( M > N -> L = M ; L = N )
).
ls(_, N, [], N).

Resources