Shallow predicate to square each number in the list - prolog

I am trying to want to create a shallow predicate called say square to square each number in the list
example :
e.g. ?-square([a,[[3]],b,4,c(5),8],X).
X=[a,[[3]],b,16,c(5),64]

Trivial.
sq(X) :-
number(X) -> X2 is X*X ; X2 = X.
square(List, Squared) :-
maplist(sq, List, Squared).
But note that square([X], X2), X=2 will not have the desired effect.

Related

Create predicates given the last n elements of a list

Example:
?-lastN([1,2,3,4],3,T).
T = [2,3,4]
this is whay i'm write:
lastN(L,N,R):- length(L,X), X1 is X-N, lastT(L, N,R).
lastT(L,0,L).
lastT(X,[H|T],L):- X2 is X-1, lastT(T,X2,L).
I assume the question was 'predicate to get last N elements in a list' and this is what you meant to do. It's a simple discarding of the first element after counting how many elements have to be discarded, right? It also does not deal with improper input at all
lastN(L,N,R):- length(L,X), X1 is X-N, lastT(L,X1,R).
lastT(L,0,L).
lastT([H|T],X,L):- X2 is X-1, lastT(T,X2,L).

Adding numbers in Prolog and unifying it with same variable

Suppose I have a recursive definition which runs for say 4 times giving new value to X1 every time,and the final value of A1 should be sum of all the X1.(That is I want to implement A1=A1+X1 where X1 gets new values after every recursive call)
add(A1,X1,L1,L):-
L1 is L+1,
A1 is A1+X1.
Sum(A1,L):-
nth1(L,[1,2,4,5],X1),
add(A1,X1,L1,L),
( L1<=4 ->Sum(A1,L1)
; write('')
).
I have the feeling looking at your code and the names you use for variables, that you think that variables are somehow always global. And you don't have to "declare" or "instantiate" a number with N is 1. So your code could be:
main :-
add(2, 3).
add(X, Y) :-
sum(X, Y, Sum), write(Sum), /* X is Sum */ write(X), nl.
sum(X, Y, Sum) :-
Sum is X + Y.
Saying X is Sum means in this case that X and Sum must be the same number.
Now, if you wanted to actually add two things together and keep the new sum, you would have to use a new variable for it, since this is how variables work:
add(X, Y) :-
sum(X, Y, Sum), write(Sum),
nl,
sum(Sum, X, X1), write(X1),
nl.
Variables, once bound to a value (unified) cease to be variable. They become an immutable object.
However, to accomplish what you want (as I understand your problem statement), you can say something like this:
sum(A,X,1,S) :- % one iteration, and we're done. Just compute the sum of A+X.
S is A+X . % - just compute the sum of A+X and unify it with S.
sum(A,X,N,S) :- % otherwise...
N > 1 , % - so long as N > 1 ,
N1 is N-1 , % - decrement N
A1 is A+X , % - compute a new A, the sum of the current A+X
sum(A1,X,N1,S) . % - and recurse down, passing the new values.

Prolog Bubblesort

I'm trying to best understand everything about this code. This is how I currently perceive what's happening:
So I can see if X > Y we swap the elements, if not we recurse down the sublist until we find an X that X > Y, if we do not, then the list is sorted.
Problems I'm having is I don't really understand the base case, bubblesort(Sorted, Sorted). I thought you would need a base case for an empty list? I would really appreciate if someone could describe a sort of step by step description of this program.
bubblesort(List,Sorted) :-
swap(List,List1),
!,
bubblesort(List1,Sorted).
bubblesort(Sorted,Sorted).
swap([X,Y|Rest],[Y,X|Rest]) :- % swaps X with Y if gt(X,Y) is true.
gt(X,Y).
swap([Z|Rest],[Z|Rest1]) :- % calls swap on sublists excluding the heads.
swap(Rest,Rest1).
gt(X,Y) :- % true if X is greater than Y.
X > Y.

Prolog: Rotate list n times right

Working on a predicate, rotate(L,M,N), where L is a new list formed by rotating M to the right N times.
My approach was to just append the tail of M to its head N times.
rotate(L, M, N) :-
( N > 0,
rotate2(L, M, N)
; L = M
).
rotate2(L, [H|T], Ct) :-
append(T, [H], L),
Ct2 is Ct - 1,
rotate2(L, T, Ct2).
Currently, my code returns L equal to the original M, no matter what N is set to.
Seems like when I'm recursing, the tail isn't properly moved to the head.
You can use append to split lists, and length to create lists:
% rotate(+List, +N, -RotatedList)
% True when RotatedList is List rotated N positions to the right
rotate(List, N, RotatedList) :-
length(Back, N), % create a list of variables of length N
append(Front, Back, List), % split L
append(Back, Front, RotatedList).
Note: this only works for N <= length(L). You can use arithmetic to fix that.
Edit for clarity
This predicate is defined for List and N arguments that are not variables when the predicate is called. I inadvertently reordered the arguments from your original question, because in Prolog, the convention is that strictly input arguments should come before output arguments. So, List and N and input arguments, RotatedList is an output argument. So these are correct queries:
?- rotate([a,b,c], 2, R).
?- rotate([a,b,c], 1, [c,a,b]).
but this:
?- rotate(L, 2, [a,b,c]).
will go into infinite recursion after finding one answer.
When reading the SWI-Prolog documentation, look out for predicate arguments marked with a "?", as in length. They can be used as shown in this example.

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