Related
I'm new to Prolog and I am having trouble with recursion and nested lists.
I want a predicate called getCommon(Number, List, X) which does the following:
getCommon(2, [[2,3], [2,5], [3,5]], X).
X = [[2,3], [2,5]].
I tried this but it returns an empty list and I am very confused as to why:
getCommon(_,[],_).
getCommon(Elem, [PointsH|PointsT], CommonPoints):-
nth0(0, PointsH, CurrElem),
(CurrElem = Elem -> append(CommonPoints,[PointsH],NewCommonPoints) ;append(CommonPoints,[],NewCommonPoints)),
getCommon(Elem, PointsT, NewCommonPoints).
Your code does not work because the recursion base case is not well defined and also because predicate append/3 is not properly used. Try the following code:
get_common(_, [], []).
get_common(K, [[K,Y]|Points], [[K,Y]|Rest]) :-
get_common(K, Points, Rest).
get_common(K, [[X,_]|Points], Rest) :-
dif(K,X),
get_common(K, Points, Rest).
Examples:
?- get_common(2, [[2,3], [3,2], [2,5], [3,7]], Common).
Common = [[2, 3], [2, 5]] ;
false.
?- get_common(3, [[2,3], [3,2], [2,5], [3,7]], Common).
Common = [[3, 2], [3, 7]] ;
false.
?- get_common(2, [[2,3], [K,2], [2,5], [3,7]], Common).
K = 2,
Common = [[2, 3], [2, 2], [2, 5]] ;
Common = [[2, 3], [2, 5]],
dif(K, 2) ;
false.
I am just starting to learn Prolog, and I am having troubles wrapping my head around recursive concepts. Right now, solely for the purpose of practice, I am trying to write a program that appends 10 numbers to a list and then prints out that list.
The self-imposed rule for this program is that the list has to be 'declared' (I am not sure if that is the correct word for Prolog) in a main predicate, which calls another predicate to append numbers to the list.
This is what I have so far, and I know it won't work because I am trying to redefine List at the end of the addToList predicate, which is not allowed in the language.
% Entry point that declares a list (`List`) to store the 10 numbers
printList(List) :-
addToList(0, List),
writeln(List).
% Base case - once we hit 11 we can stop adding numbers to the list
addToList(11, _).
% First case - this predicate makes adding the first number easier for me...
addToList(0, List) :-
append([], [0], NewList),
addToList(1, NewList),
append([], NewList, List). % This is valid, but List will just be [0] I think..
% Cases 1-10
addToList(Value, List) :-
append(List, [Value], NewList),
NextVal is Value+1,
addToList(NextVal, NewList),
append([], NewList, List). % This is INVALID since List is already defined
This program would be started with:
printList(List).
Is there a simple way to change up the broken program I have written up to make it work correctly? I am super lost on how to get the numbers stored in List.
You are thinking procedurally, in prolog you cannot change variables. You are trying to construct the list yourself. In prolog-style you try to declare the constraints of the list you want. If nlist/2 is a predicate that gives a list of N numbers then what exactly are it's properties? nlist(0, []). and if nlist(N, Xs) then nlist(N+1, [N+1 | Xs]). So you just write these and let prolog take care of the construction.
nlist(0, []).
nlist(N, [N | Xs]) :-
N>0, N1 is N-1,
nlist(N1, Xs).
If you are confused how the recursion calls are taking place, try using trace/0 or trace/1. You can see how the calls are being done in the following trace. You can get this by calling trace(nlist).
?- nlist(3, X).
T Call: nlist(3, _78)
T Call: nlist(2, _902)
T Call: nlist(1, _1464)
T Call: nlist(0, _2026)
T Exit: nlist(0, [])
T Exit: nlist(1, [1])
T Exit: nlist(2, [2, 1])
T Exit: nlist(3, [3, 2, 1])
X = [3, 2, 1]
A more procedural style code will be as follows
addToList(11, A, A).
% Cases 1-10
addToList(Value, List, NewList) :-
Value < 11, append(List, [Value], Temp),
NextVal is Value+1,
addToList(NextVal, Temp, NewList).
This gives the middle parameter is the accumulator. When you reach 11 the accumulator is the answer.
?- addToList(1, [], X).
X = [1, 2, 3, 4, 5, 6, 7, 8, 9|...]
?- addToList(5, [], X).
X = [5, 6, 7, 8, 9, 10]
Look at the sample trace and the difference between them in nlist and addToList. Try to figure out the differences and why the are happening.
?- addToList(7, [], X).
T Call: addToList(7, [], _33565254)
T Call: addToList(8, [7], _33565254)
T Call: addToList(9, [7, 8], _33565254)
T Call: addToList(10, [7, 8, 9], _33565254)
T Call: addToList(11, [7, 8, 9, 10], _33565254)
T Exit: addToList(11, [7, 8, 9, 10], [7, 8, 9, 10])
T Exit: addToList(10, [7, 8, 9], [7, 8, 9, 10])
T Exit: addToList(9, [7, 8], [7, 8, 9, 10])
T Exit: addToList(8, [7], [7, 8, 9, 10])
T Exit: addToList(7, [], [7, 8, 9, 10])
X = [7, 8, 9, 10]
Here is my solution:
printSeries(_,[],0):-!.
printSeries(S,[S|T],C):-
S1 is S+1,
C1 is C-1,
printSeries(S1,T,C1).
?- printSeries(7,L,5).
L = [7, 8, 9, 10, 11]
The predicate can be used to print any series using a starting number and how many times one wants to increment it. A very easy approach is using counter. The first predicate is saying that regardless of the starting number, and whatever is in the list, if the counter reaches 0 the program should cut (meaning stop). The second predicate we have the starting number, and the list to which we are telling it that you have to start the list with the starting number, and lastly the counter. Next we increment the starting number by 1. Decrease the counter by 1. Then redo everything by giving the new values to the predicate.
?-printSeries(1,L,10).
L = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
For my assignment I need to create a list of all the possible shifts (rotations) of another list in prolog. For example,
Prototype: all_shifts(+A,-R,+L,+S) *S will always start at 1*
?- length([1,2,3,4],L), all_shifts([1,2,3,4],R,L,1).
L = 4,
R = [[2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]].
Currently, I have a program that shifts it to the left once.
one_shift(A, R) :-
rotate(left, A, R).
rotate(left, [H|T], L) :- append(T, [H], L).
However, I need to create another program in which the final result (R) contains all of the possible shifts. Recursion in prolog is really beginning to confuse me, but I'm pretty sure that's whats required. Any help would be really appreciated.
Stay logically pure using same_length/2 and append/3!
list_rotations(Es, Xss) :-
same_length(Es, [_|Xss]),
rotations_of(Xss, Es).
rotations_of([], _Es).
rotations_of([Xs|Xss], Es) :-
same_length([_|Xss], Suffix),
same_length(Es, Xs),
append(Suffix, Prefix, Xs),
append(Prefix, Suffix, Es),
rotations_of(Xss, Es).
Sample query:
?- list_rotations([A,B,C,D], Xss).
Xss = [[B,C,D,A],
[C,D,A,B],
[D,A,B,C]]. % succeeds deterministically
A solution to your problem could be:
rotatelist([H|T], R) :- append(T, [H], R).
rotate(L,LO,LL):-
rotatelist(L,L1),
\+member(L1,LO),!,
append([L1],LO,L2),
rotate(L1,L2,LL).
rotate(_,L,L).
?- rotate([1,2,3,4],[],L).
L = [[1, 2, 3, 4], [4, 1, 2, 3], [3, 4, 1, 2], [2, 3, 4, 1]]
Simply rotates the list and checks if this list has already been inserted in the output list. If not the recursion continues, otherwise it returns the list in L. I've inserted the cut ! just to have only the list with all the possible rotations. If you want generate also the other lists just remove it...
If instead you want a solution with the prototype you provide, it could be:
rotatelist([H|T], R) :- append(T, [H], R).
all_shifts(_,[],I,I).
all_shifts(L,Result,Len,I):-
I < Len,
rotatelist(L,LO),
I1 is I+1,
all_shifts(LO,R1,Len,I1),
append([LO],R1,Result).
?- length([1,2,3,4],L), all_shifts([1,2,3,4],R,L,1).
L = 4,
R = [[2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]]
The idea is basically the same as before... Note that this second solution is not tail recursive.
I want to create an intersection of lists of lists in prolog. (Matrix, with lists as cells)
I have to handle only the case, when number of rows and columns are the same (Rectangular). The lists are ordered, and does not contain any duplicate elements (they are ord_sets).
How could I do that?
Example: (3 rows, 3 columns)
A:
[[[1,2],[3,2,1],[3,4,5]],
[[1,2],[3,2,1],[3,4,5]],
[[1,2],[3,2,1],[3,4,5]]]
B:
[[[1],[3,2,1],[3,4,5]],
[[1,2],[2,1],[3,4]],
[[1,2],[3,2,1],[3,9,10,4,5]]]
C:
[[[1],[3,2,1],[3,4,5]],
[[1,2],[2,1],[3,4]],
[[1,2],[3,2,1],[3,4,5]]]
Thank you for the help!
Most Prolog interpreters already have a predicate to calculate the intersection between two lists: intersection/3. For example:
?- intersection([3,2,1], [3,9,10,4,5], R).
R = [3].
We can use maplist/3 to process an entire row of such lists:
?- maplist(intersection, [[1,2],[3,2,1],[3,4,5]], [[1],[3,2,1],[3,4,5]], C).
C = [[1], [3, 2, 1], [3, 4, 5]].
And by using another maplist/3 we process the matrices:
?- maplist(maplist(intersection),[[[1,2],[3,2,1],[3,4,5]], [[1,2],[3,2,1],[3,4,5]], [[1,2],[3,2,1],[3,4,5]]], [[[1],[3,2,1],[3,4,5]],[[1,2],[2,1],[3,4]],[[1,2],[3,2,1],[3,9,10,4,5]]], C).
C = [[[1], [3, 2, 1], [3, 4, 5]], [[1, 2], [2, 1], [3, 4]], [[1, 2], [3, 2, 1], [3, 4, 5]]].
So we can do the processing with:
intersect_matrix(A, B, C) :-
maplist(maplist(intersection), A, B, C).
I'm trying to write a predicate that divides a list into N parts.
This is what I have so far.
partition(1, List, List).
partition(N, List, [X,Y|Rest]):-
chop(List, X, Y),
member(NextToChop, [X,Y]), %Choose one of the new parts to chop further.
NewN is N-1,
partition(NewN, NextToChop, Rest).
chop(List, _, _):-
length(List, Length),
Length < 2, %You can't chop something that doesn't have at least 2 elements
fail,!.
chop(List, Deel1, Deel2):-
append(Deel1, Deel2, List),
Deel1 \= [],
Deel2 \= [].
The idea is to keep chopping parts of the list into two other parts until I have N pieces.
I have mediocre results with this approach:
?- partition(2, [1,2,3,4], List).
List = [[1], [2, 3, 4], 1] ;
List = [[1], [2, 3, 4], 2, 3, 4] ;
List = [[1, 2], [3, 4], 1, 2] ;
List = [[1, 2], [3, 4], 3, 4] ;
List = [[1, 2, 3], [4], 1, 2, 3] ;
List = [[1, 2, 3], [4], 4] ;
false.
So I get what I want, but I get it two times and there are some other things attached.
When dividing into 3 parts things get worse:
?- partition(3, [1,2,3,4], List).
List = [[1], [2, 3, 4], [2], [3, 4], 2] ;
List = [[1], [2, 3, 4], [2], [3, 4], 3, 4] ;
List = [[1], [2, 3, 4], [2, 3], [4], 2, 3] ;
List = [[1], [2, 3, 4], [2, 3], [4], 4] ;
List = [[1, 2], [3, 4], [1], [2], 1] ;
List = [[1, 2], [3, 4], [1], [2], 2] ;
List = [[1, 2], [3, 4], [3], [4], 3] ;
List = [[1, 2], [3, 4], [3], [4], 4] ;
List = [[1, 2, 3], [4], [1], [2, 3], 1] ;
List = [[1, 2, 3], [4], [1], [2, 3], 2, 3] ;
List = [[1, 2, 3], [4], [1, 2], [3], 1, 2] ;
List = [[1, 2, 3], [4], [1, 2], [3], 3] ;
false.
Another idea is using prefix but I don't know how that would really work. To use that I should be able to let Prolog know that it needs to take a prefix that's not too short and not too long either, so I don't take a prefix that's too long so there's nothing left for a next recursion step.
Can anyone point me in the right direction?
Little clarification: the predicate should return all posibilities of dividing the list in N parts (not including empty lists).
When describing relations that involve lists, DCGs are often very useful. Consider:
list_n_parts(List, N, Parts) :-
length(Parts, N),
phrase(parts(Parts), List).
parts([]) --> [].
parts([Part|Parts]) --> part(Part), parts(Parts).
part([P|Ps]) --> [P], list(Ps).
list([]) --> [].
list([L|Ls]) --> [L], list(Ls).
Sample query:
?- list_n_parts([1,2,3,4], 2, Ps).
Ps = [[1], [2, 3, 4]] ;
Ps = [[1, 2], [3, 4]] ;
Ps = [[1, 2, 3], [4]] ;
false.
Here is the basic way I'd use to implement that (using append/2 and length/2) :
list_n_parts(List, Parts, Result) :-
length(Result, Parts),
append(Result, List).
Now, that doesn't totally complies to your expectations : it allows for [].
One idea to fix that is to use a maplist call to format the Resulting list beforehand :
list_n_parts(List, Parts, Result) :-
length(Result, Parts),
using copy_term/2, the maplist/2 call looks like :
maplist(copy_term([_|_]), Result),
using functor/3 (credits to #false), it would look like :
maplist(functor('.', 2), Result),
using lambda.pl you could write :
maplist(\[_|_]^true, Result),
since the '\' already performs a term copy (thanks #false).
The only thing left is the append/2 call:
append(Result, List).
Another idea would be to use forall/2 filtering (maybe simpler to get, but worse in complexity) :
list_n_parts(List, Parts, Result) :-
length(Result, Parts),
append(Result, List),
forall(member(X, Result), X \= []).
etc...