forming successive list of numbers in Prolog [duplicate] - prolog

I am trying to keep only the first element and the last element for a list which contains only consecutive integers.
For example:
?- remove([1,2,3,4,5], NewList).
NewList = [1,5].
I can only successfully keep the last element:
remove([], []).
% for consecutive integers in the list
remove([ Head | Tail ], NewList) :-
check_consecutive(Head, Tail),
remove(Tail, NewList).
% for the case when the list is empty
remove([ Head | Tail ], [ Head | NewList ]) :-
not(check_consecutive(Head, Tail)),
remove(Tail, NewList).
check_consecutive(Num, [ Head | _ ]) :-
Num is Head - 1.
I have been tying to keep the first element, but it keeps giving me the last element.
If there are some elements which is not consecutive, it should do some thing like:
?- remove([1,2,4,5,6,8,3], NewList).
NewList = [[1,6], 8, 3].
Any assistance is appreciated.

To solve this problem you have to handle different cases, here the solution then the comment:
last([E],E).
last([_|T],E):-
last(T,E).
remove([],[]).
remove([A],[A]).
remove([A,B],[A,B]).
remove([A|B],[A,Last]):-
last(B,Last).
findElementsR([A,B],LT,LOT,LO):-
B =< A,
append(LT,[A],LT1),
remove(LT1,LRem),
append(LOT,[LRem,[B]],LO).
findElementsR([A,B|T],LT,LOT,LO):-
B =< A,
append(LT,[A],LT1),
remove(LT1,LRem),
append(LOT,[LRem],LOT1),
findElementsR([B|T],[],LOT1,LO).
findElementsR([A,B],LT,LOT,LO):-
B is A+1, %consecutive
append(LT,[A,B],LTO),
remove(LTO,RM),
append(LOT,[RM],LO).
findElementsR([A,B|T],LT,LOT,LO):-
B is A+1, %consecutive
append(LT,[A],LTO),
findElementsR([B|T],LTO,LOT,LO).
findElements(L,LO):-
findElementsR(L,[],[],LO).
?- findElements([3,1,2,3,2,3,4,5,2,3,4],L).
L = [[3], [1, 3], [2, 5], [2, 4]]
false
So, first of all, i've defined last/2 that simply, given a list as an input, returns the last element
?- last([1,2,3],L).
L = 3
Then with remove/3 i get the list composd by th first and the last element.
findElements/2 is used to call findElementsR/4 (to make it tail recursive). findElements/4 finds a list of consecutive elements and then calls remove/2 to get the first and the last.

Related

Finding subsequences from list

Hello i can't figure out how to solve an assignment. I am supposed to find the consecutive element combinations from a list. For example: the list [1,2,3]
should give me [1],[2],[3], [1,2], [2,3], [1,2,3] but the problem i have is that my attempt also gives me [1,3]
Code:
subseq([], []).
subseq([H|T], [H|R]) :- subseq(T, R).
subseq([_|T], R) :- subseq(T, R).
The problem here is that on each element of the given list, you have two clauses:
the second line where you select the item; and
the third line where you do not select the item.
So that means you generate all lists where for every item it is an option to include it, or exclude it.
For a subsequence, the ones defined in your question, it is a different story: you basically have two selection points:
the point where you "start" the subsequence; and
the point where you "stop" the subsequence.
Stopping a subsequence is actually the same as generating a prefix:
myprefix(_, []).
myprefix([H|T], [H|T2]) :-
myprefix(T, T2).
So now for a subsequence, we only need to branch over the starting point, and then add a prefix of the remaining list, like:
subsequence([H|T], [H|T2]) :-
myprefix(T, T2).
subsequence([_|T], T2) :-
subsequence(T, T2).
This then yields the expected:
?- subsequence([1, 2, 3], X).
X = [1] ;
X = [1, 2] ;
X = [1, 2, 3] ;
X = [2] ;
X = [2, 3] ;
X = [3] ;
false.

Prolog Remove the elements between the first and the last elements in a list

I am trying to keep only the first element and the last element for a list which contains only consecutive integers.
For example:
?- remove([1,2,3,4,5], NewList).
NewList = [1,5].
I can only successfully keep the last element:
remove([], []).
% for consecutive integers in the list
remove([ Head | Tail ], NewList) :-
check_consecutive(Head, Tail),
remove(Tail, NewList).
% for the case when the list is empty
remove([ Head | Tail ], [ Head | NewList ]) :-
not(check_consecutive(Head, Tail)),
remove(Tail, NewList).
check_consecutive(Num, [ Head | _ ]) :-
Num is Head - 1.
I have been tying to keep the first element, but it keeps giving me the last element.
If there are some elements which is not consecutive, it should do some thing like:
?- remove([1,2,4,5,6,8,3], NewList).
NewList = [[1,6], 8, 3].
Any assistance is appreciated.
To solve this problem you have to handle different cases, here the solution then the comment:
last([E],E).
last([_|T],E):-
last(T,E).
remove([],[]).
remove([A],[A]).
remove([A,B],[A,B]).
remove([A|B],[A,Last]):-
last(B,Last).
findElementsR([A,B],LT,LOT,LO):-
B =< A,
append(LT,[A],LT1),
remove(LT1,LRem),
append(LOT,[LRem,[B]],LO).
findElementsR([A,B|T],LT,LOT,LO):-
B =< A,
append(LT,[A],LT1),
remove(LT1,LRem),
append(LOT,[LRem],LOT1),
findElementsR([B|T],[],LOT1,LO).
findElementsR([A,B],LT,LOT,LO):-
B is A+1, %consecutive
append(LT,[A,B],LTO),
remove(LTO,RM),
append(LOT,[RM],LO).
findElementsR([A,B|T],LT,LOT,LO):-
B is A+1, %consecutive
append(LT,[A],LTO),
findElementsR([B|T],LTO,LOT,LO).
findElements(L,LO):-
findElementsR(L,[],[],LO).
?- findElements([3,1,2,3,2,3,4,5,2,3,4],L).
L = [[3], [1, 3], [2, 5], [2, 4]]
false
So, first of all, i've defined last/2 that simply, given a list as an input, returns the last element
?- last([1,2,3],L).
L = 3
Then with remove/3 i get the list composd by th first and the last element.
findElements/2 is used to call findElementsR/4 (to make it tail recursive). findElements/4 finds a list of consecutive elements and then calls remove/2 to get the first and the last.

Rotate a list in prolog recursively

I'm trying to rotate a list in prolog recursively but it does not work as expected.
Code:
rot([],[]).
rot([H|T1], [T2|H]):-rot(T1,T2).
Output:
?- rot([1,2,3], V).
V = [[[[]|3]|2]|1]
Expected output:
?- rot([1,2,3], V).
V = [3,2,1]
Could anyone explain me why my code does not work?
Since Prolog is untyped, you can indeed write something like [List|Element], but if you want a list to make sense, the only way you can construct lists is like [Element|List]. So [T2|H] does not make sense at all. In that case T2 should be an element, and H a list (or the empty list []).
You will need to define two predicates:
the main predicate (rot/2) that simply pops the head from the given list and calls the recursive predicate; and
the recursive predicate (here rot/3) that simply passes all elements of the given list and emits the original head as tail element.
Together this works like:
%main predicate rot/2
rot([],[]).
rot([H|T1],T2) :-
rot(T1,H,T2).
%recursive predicate rot/3
rot([],Last,[Last]).
rot([H|T1],Last,[H|T2]) :-
rot(T1,Last,T2).
Your code doesn't work because in an expression like [H|T], H is an element of the list and T is the tail of the list--also a list. For instance:
?- [H|T] = [1,2,3].
H = 1,
T = [2, 3].
So what happens when you switch that around?
?- [H|T] = [1,2,3], X = [T|H].
H = 1,
T = [2, 3],
X = [[2, 3]|1].
See the problem?
The problem is with the second clause. What I do is to rotate the tail of the first list inside L1 and then call append with L1 and the first element and assign the result to L (the second argument)
my-append([], L, L).
my-append([H|T], L, [H|R]) :- my-append(T, L, R).
rot([], []).
rot([H|T], L) :- rot(T, L1), my-append(L1, H, L).

Prolog recursively append the list

Here's a code which recursively add the element X at the end of the list.
app(X, [], [X]).
app(X, [Y | S], [Y | S2]) :- app(X, S, S2).
Could anyone explain me how it works? Where's the return statement, what exactly the app(X, S, S2) [Y | S], [Y | S2] do?
You don't need return statement everything is done by unification (simply pattern matching). The clause:
app(X, [Y | S], [Y | S2])
states that the second argument is a list with head Y and tail S and the third argument is a list with head Y and tail S2. So it forces (by using unification) the heads of the two lists to be the same. Recursively the two lists become identical except the fact that the third argument list has one more element in the end (element X) and this is defined by the first clause. Note that second clause only works for lists with one or more elements. So as a base of the recursion when we examine the empty list (in the second parameter) then the third list due to first clause contains only one more element the element X.
Prolog programs are made by defining facts and rules. You define facts and rules, and Prolog interpreter tries to come up with solutions to make them true. Other than this basic concept, you need to know two other important concepts which Prolog programmers use extensively.
These are:
Input and Output parameters: There are no return statements in Prolog. Some variables will be results (outputs) and some others will be the inputs. In your program, the first and second parameters are input and the last one is the output.
Pattern Matching: If a list is expressed as [Head|Tail]. Head is the first element and Tail is a list of the remaining elements.
When you call app, for example, as app(5, [1, 2, 3, 4], L)., Prolog interpreter tries to come up with values for L such that app is true.
Prolog interpreter is solving the problem in the following steps:
In order to make app(X, [Y | S], [Y | S2]) true, the first element of the last parameter need to become Y. So, in my example, L becomes [1, S2].
Then it tries to match the rule app(X, S, S2). Here S is [2, 3, 4] and S2 is the output parameter for the next run. Then Step 1 gets repeated but with app(5, [2, 3, 4], S2) and after that S2 becomes [2, S2]. So, L, now, becomes [1, 2, S2].
This same thing gets repeated (recursion) and L is populated as [1, 2, 3, 4, S2].
Now, the second parameter is empty. So, the first fact app(X, [], [X]) is matched. In order to make this true, the last parameter becomes a list containing just X (which is 5 in this case), which results in L being [1, 2, 3, 4, 5].

Create a newlist with elements of the sublists by my List

I have this list :
C = [[1,0],[2,3],[1,2],[1,3]]
I'll like find if the number 1 included in a sublist inside my list in position [1,_ ] and i like to save to a list Newlist the number of X ..... [1,X].
I will give an example... i have the list C and i am searching for sublist which first element it's 1 and give me the Newlist.
The Newlist must be : Newlist=[0,2,3]
It had the second element of the sublists who has the number 1 at the first element.
If you use SWI-Prolog with module lambda.pl, (you can find it at http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/lambda.pl) you can write
:- use_module(library(lambda)).
my_filter(V, L, R) :-
foldl(V+\X^Y^Z^(X = [V,W]
-> append(Y, [W], Z)
; Z = Y),
L, [], R).
nth0/3 allows to access list' elements by index:
?- C = [[1,0],[2,3],[1,2],[1,3]], findall(P, nth0(P, C, [1,_]), NewList).
C = [[1, 0], [2, 3], [1, 2], [1, 3]],
NewList = [0, 2, 3].
edit I'm sorry I didn't read the question right. nth0 is misleading. Could be instead
findall(E, member([1,E], C), NewList)
You need a "filter". This is what it could look like:
filter_1_at_pos_1([], []). % The new list is empty when the input list is empty
filter_1_at_pos_1([[1,X]|Sublist], [X|Xs]) :- % The first element is 1 so the
% second element belongs to the
% new list
!, filter_1_at_pos_1(Sublist, Xs). % filter the remainder of the list
filter_1_at_pos_1([[N,_]|Sublist], Xs) :-
N \== 1, % The first element is not 1, ignore the second element
!, filter_1_at_pos_1(Sublist, Xs).
As #mbratch suggested, just define the solution for one element of the input list for each possible condition, in this case 1) empty list 2) first element is 1 and 3) first element is not 1.
?- C = [[1,0],[2,3],[1,2],[1,3]], filter_1_at_pos_1(C, NewList).
C = [[1, 0], [2, 3], [1, 2], [1, 3]],
NewList = [0, 2, 3].
The cuts make the predicate deterministic. The cut in the last clause is not necessary.

Resources