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]
Related
I am really sorry for previous question, it's my first time post question on this website and I really didn't know I shouldn't post quesion like that.
It was my first time using prolog. Actually I spent more than 5 hours on this question but still cannot fully solve it, I tried to tear this question apart and here is what remain to be solved:
How to put the successive increasing whole numbers into a sublist in origin list.
eg. [3,5,1,2,3,7,8,2] to [3,5,[1,2,3],[7,8],2]
Here is what I wrote, can someone tell me how to fix the code? Thanks.
% empty List
chop_up([], []).
% single item list
chop_up([X], [X]).
% continue if the first number is not part of a sequence
chop_up(List, NewList):-
List = [First | Tail],
Tail = [Second | _],
First =\= Second - 1,
chop_up(Tail, NewList2),
NewList = [First | NewList2].
% if it is part of a sequence
chop_up(List, NewList):-
List = [First | Tail],
Tail = [Second | Tail2],
First is Second - 1,
chop_up(Tail, NewList2),
NewList = [[First] | NewList2].
enter image description here
Thank you for updating your question to show us what you tried!
Like all Prolog beginners, you are trying to do too much at once. This is normal! But you have to learn and get used to a way of thinking that is different from other programming languages. Almost always you have to decompose your problem into several subproblems that you then put together to get the final program.
So let's try to solve only one part of the problem first: Given a nonempty list, decompose it into successive elements at the front and into all the remaining elements. That is, we want something like this:
?- list_successive_rest([1, 2, 4, 3], Succ, Rest).
Succ = [1, 2],
Rest = [4, 3] .
If we can write this definition, then we should be able to iterate over the Rest to chop it up further.
Here is a definition of list_successive_rest/3. Note how it follows the structure of your attempt for chop_up/2, but it's shorter and simpler because we only look at a successive prefix of the list, not all of the list at once:
list_successive_rest([X], [X], []).
list_successive_rest([A, B | Xs], [A], [B | Xs]) :-
A + 1 =\= B.
list_successive_rest([A, B | Xs], [A | Successive], Rest) :-
A + 1 =:= B,
list_successive_rest([B | Xs], Successive, Rest).
(This is also simpler than your version because I match lists of at least two elements as [A, B | Xs] rather than [A | Tail] and Tail = [B | Tail2]. It's a good idea to get used to this syntax.)
We can call this successively to decompose a list into successive parts:
?- list_successive_rest([1, 2, 4, 3], Succ, Rest), list_successive_rest(Rest, Succ2, Rest2), list_successive_rest(Rest2, Succ3, Rest3).
Succ = [1, 2],
Rest = [4, 3],
Succ2 = [4],
Rest2 = Succ3, Succ3 = [3],
Rest3 = [] ;
false.
Defining chop_up/2 is now easy by using the above predicate to peel off successive prefixes of the list iteratively:
chop_up([], []).
chop_up(List, [Succ | Chopped]) :-
list_successive_rest(List, Succ, Rest),
chop_up(Rest, Chopped).
Note that chop_up/2 is recursive, and it uses list_successive_rest/3, which is recursive as well. Trying to write all this in one recursive predicate would be harder and lead to less readable code.
Let's try the above test, and your test case:
?- chop_up([1, 2, 4, 3], Chopped).
Chopped = [[1, 2], [4], [3]] ;
false.
?- chop_up([3,5,1,2,3,7,8,2], Chopped).
Chopped = [[3], [5], [1, 2, 3], [7, 8], [2]] ;
false.
This doesn't actually produce the exact format you wanted: Singleton elements are singleton lists rather than "naked" members of the outer list. I think this is better this way, but your teacher may disagree. In that case, changing this small detail is an exercise for you.
I conseived much more elegant way with DCG!
chunk_list([])-->[].
chunk_list([C|Rest])-->chunk(C),chunk_list(Rest).
chunk(Ret)-->[First],consecutive(First,Last),{First=:=Last->Ret is First;Ret = [First,Last]}.
consecutive(Prev,Last)-->[Current],{Current is Prev+1},consecutive(Current,Last).
consecutive(Prev,Prev)-->[].
Test:
?- phrase(chunk_list(R),[1,2,3,6,7,3,3,2,3,4,6],[]).
R = [[1, 3], [6, 7], 3, 3, [2, 4], 6]
maybe it could be reversible with more lavor.
I.E. convert [[1, 3], [6, 7], 3, 3, [2, 4], 6] into [1,2,3,6,7,3,3,2,3,4,6]
I also tried for my prolog training.
terrible program but does work anyway.
I tested this in ECLiPSe but it will work with few modification in other environment(may be only deleting :-lib(listut))
call like this:
chunk([4,5,6,3,4,4,57,3,4,5,7,2,3,4,5,7,7,54,3],Ret).
Program:
:-lib(listut).
chunk(List,Ans):-
chunk_sub(List,0,[],List1),
first_and_lasts(List1,Ans),
!.
chunk_sub([],_,Ret,Reverse):-reverse(Ret,Reverse),!.
chunk_sub([Current|Rest],Prev,[NowList|RetRest],Ret):-
Current =:= Prev+1,
append(NowList,[Current],NextList),
chunk_sub(Rest,Current,[NextList|RetRest],Ret).
chunk_sub([Current|Rest],_,NowList,Ret):-
chunk_sub(Rest,Current,[[Current]|NowList],Ret).
first_and_lasts([],[]):-!.
first_and_lasts([FirstList|RestLists],[Converted|RestRet]):-
length(FirstList,Len),
(
Len=:=1->
([OneElem]=FirstList,Converted=OneElem);
(
nth1(1,FirstList,Smallest),
nth1(Len,FirstList,Biggest),
Converted=[Smallest,Biggest]
)
),
first_and_lasts(RestLists,RestRet).
Finally I did it!
this is reversible(generalized) version.This program works cleverly.
It was very fun developing this.
Code:
chunk_list([])-->[],!.
chunk_list([Chunk|Rest])-->chunk(Chunk),!,chunk_list(Rest).
chunk([First,Last])-->sequence([First,Last]),{First<Last}. % sequence
chunk(Val)-->sequence([Val,Val]). % isolated number
sequence([First,Last])-->
{(number(First),number(Last))->First<Last;true},
[First],
{succ(First,Second)},sequence([Second,Last]).
sequence([Val,Val])-->[Val].
Test:
[eclipse 4]: phrase(chunk_list([2,[2,6],[3,5],3,7,[1,3]]),Ret).
Ret = [2, 2, 3, 4, 5, 6, 3, 4, 5, 3, 7, 1, 2, 3]
Yes (0.00s cpu)
[eclipse 5]: phrase(chunk_list(Ret),[3,4,5,2,1,6,7,88,9,4,5,6,7,2,1,2,3]).
Ret = [[3, 5], 2, 1, [6, 7], 88, 9, [4, 7], 2, [1, 3]]
Yes (0.00s cpu)
[eclipse 6]: phrase(chunk_list([[2,4],A,[2,8],3]),[2,B,4,6,2,C,4,5,6,7,D,E]).
A = 6
B = 3
C = 3
D = 8
E = 3
Yes (0.00s cpu)
I'd like to create a predicate arrayLEQ(L,N) that is true when L = [1,2,3,...,N].
I tried to do it recursively:
arrayLEQ(L,N) :- arrayLEQ([],L,1,N).
arrayLEQ(L1,L2,N,N) :- append(L1,[N],L2).
arrayLEQ(L1,L2,F,N) :- Fnext is F+1, append(L1,[F],L1n), arrayLEQ(L1n,L2,Fnext,N).
At first I thought that it will work, but sadly it doesn't.
When I do:
?- arrayLEQ(L,5) I get L = [1,2,3,4,5] which is the right answer, but Prolog is ready to look for another answer, which is not wanted.
Would you mind explaining to me what I did wrong and why Prolog tries to look for another answer to this predicate, even if it doesn't exist.
Let's have a look at tracer after the first query succeed:
?- arrayLEQ(L,5).
L = [1,2,3,4,5].
more
Redo:arrayLEQ([1, 2, 3, 4], _5040, 5, 5)
Call:_5844 is 5+1
Exit:6 is 5+1
Call:lists:append([1, 2, 3, 4], [5], _5854)
Exit:lists:append([1, 2, 3, 4], [5], [1, 2, 3, 4, 5])
Call:...
Call:_5880 is 6+1
Exit:7 is 6+1
Call:lists:append([1, 2, 3, 4, 5], [6], _5890)
Exit:lists:append([1, 2, 3, 4, 5], [6], [1, 2, 3, 4, 5, 6])
Call:arrayLEQ([1, 2, 3, 4, 5, 6], _5040, 7, 5)
Call:_5922 is 7+1
Exit:8 is 7+1
Call:lists:append([1, 2, 3, 4, 5, 6], [7], _5932)
Exit:lists:append([1, 2, 3, 4, 5, 6], [7], [1, 2, 3, 4, 5, 6, 7])
Call:arrayLEQ([1, 2, 3, 4, 5, 6, 7], _5040, 8, 5)
Call:_5970 is 8+1
Exit:9 is 8+1
and so on...
You can see that your program keeps adding element into the list, without stopping. So there are two solutions:
Adding a cut (!): arrayLEQ(L1,L2,N,N):- !, append(L1,[N],L2). It works but maybe (in my opinion) there is a better solution.
When adding an element, you don't check if you have already passed the threshod you set (in this case 5). So you just have to add F < N before doing Fnext is F+1. So: arrayLEQ(L1,L2,F,N) :- F < N, Fnext is F+1, append(L1,[F],L1n), arrayLEQ(L1n,L2,Fnext,N). (personally i prefer this solution)
So the query now (with second solution):
?- arrayLEQ(L,5).
L = [1, 2, 3, 4, 5].
more.
false.
I suggest you to not use append/3 because in this case is not necessary at all and write someting like this:
orderedList(L,N):-
orderedList(L,1,N).
orderedList([N],N,N). %you can add a cut ! here, to avoid further search
orderedList([H|T],C,N):-
C < N,
H is C,
C1 is C+1,
orderedList(T,C1,N).
?- orderedList(L,5).
L = [1, 2, 3, 4, 5]
more
false
Then if you need to return an empty list, wou can add a predicate to handle this case easily... BTW check also the question linked in the comments by #repeat
I am trying to write a Prolog code, but I can't get this to return true. I am trying to find a list, which all elements are included in two other lists. For example all list A elements are found in B and C lists each, not together.
My Prolog code is :
member(X, [X|_]).
member(X, [_|T]) :-
member(X, T).
first([H0|T0], [H0|T1], A) :-
member(H0, A),
first(T0, [H0|T1], A).
first([H0|T0], [_|T1], A) :-
first([H0|T0], T1, A).
where member predicate returns true if an element is in a list. With predicate 'first' I am trying to use member predicate to find a matching element of A and B in C list. If I find, then go further in the first list and compare its first element to second lists elements and again, if I would matching, I check with if I can find it in third list. I hope it does this, but when I run
?- first([4, 6, 4], [4, 5, 6, 4], [1, 2, 4, 6]).
it gives false and I can't figure out why. This seems as a simple attention mistake somewhere, but I just can't get my head around it.
I don't know anything about prolog, but like everyone I've been bitten by logic errors before. (=
As I have commented, you seem to lack a base case for first([], _, _). An example:
first([4], [4], [4]) :-
member(4, [4]), // quite true
first([], [4], [4]). // No matching rule, as all those assume an existing head in the first argument
I am not sure I understood your question, but allow me to try to specify further your predicate first/3:
first(+L, +L1, +L2)
succeeds if every element of L is found either in L1 or in L2.
If this is what you're looking for, then:
first([], _, _).
first([E|L], L1, L2) :-
(member(E, L1); member(E, L2)),
first(L, L1, L2).
Examples of success:
first([1, 2, 3], [1, 2, 3], [1, 2]).
first([1], [1, 2, 3], [1, 2]).
first([1, 2, 3], [1, 2, 3], []).
Examples of faiure:
first([1, 2, 3, 5], [1, 2, 3], [1, 2]).
first([7], [1, 2, 3], [1, 2]).
first([1, 2, 3], [], []).
How can I reverse pairs of some list in Prolog?
For example:
?- reversePairs([1,2,3,4,5,6,7,9], R).
R = [2,1,4,3,6,5,9,7]. % expected answer
So far, I have written the following code:
reversePairs([X,Y|Xs], ReversedList) :-
reversePairs([X,Y|Xs], [], ReversedList).
reversePairs([], ReversedList, ReversedList).
reversePairs([X,Y|Xs], Accum, ReversedList) :-
reversePairs(Xs, [X,Y|Accum], ReversedList).
My code gives me the following answer:
?- reversePairs([1,2,3,4,5,6,7,9], R).
R = [7,9,5,6,3,4,1,2]. % observed answer
How can I correct my code to get the answer I want? Any suggestion?
Simply :
reversePairs([],[]).
reversePairs([X,Y|T], [Y,X|RT]) :-
reversePairs(T, RT).
This code fails if the number of elements is odd. What do you want to do for this case ?
Here's a funny possibility with DCGs:
reverp, [B,A] --> [A,B], !, reverp.
reverp --> [].
reversePairs(L1,L2) :- phrase(reverp,L1,L2).
It will also work on lists with odd number of elements.
Sample query:
?- reversePairs([1,2,3,4,5,6,7,9], R).
R = [2, 1, 4, 3, 6, 5, 9, 7].
?- reversePairs([1,2,3,4,5,6,7,8,9], R).
R = [2, 1, 4, 3, 6, 5, 8, 7, 9].
Can be easily generalized to N elements:
revern(N), Lr --> { length(L,N) }, L, !, { reverse(L,Lr) }, revern(N).
revern(_) --> [].
reverseNuples(N,L1,L2) :- phrase(revern(N),L1,L2).
Sample query:
?- reverseNuples(3,[1,2,3,4,5,6,7,9],R).
R = [3, 2, 1, 6, 5, 4, 7, 9].
As #repeat mentions in a comment below, reversePairs is not symmetric: the query
?- reversePairs(L,[2,1,4,3,6,5]).
will loop forever. To fix that, we can use same_length/2, to ensure that both terms are lists with same length:
reversePairs(L1,L2) :-
same_length(L1,L2),
phrase(reverp,L1,L2).
reverse([], X, X).
reverse([H|Original], Result, Reverse) :-
reverse(Original, Result, [H|Reverse]).
?- reverse([1,2,3], X, []).
X = [3,2,1].
So above is a fairly simple Prolog program to reverse a list. I'm just looking for someone to explain to me how the Reverse variable in the reverse rule ends up with the result. From my thinking, I'm adding the head of the original list to the head of a new list Reverse thus reversing the list. Nowhere am I interacting with the variable Result, so why does it hold anything at all?
I've been really stumped on this for a few days now and would be really grateful if anyone could clear this up!
PS. I'm also struggling with why reverse([], X, X). is required for this to work.
If you activate tracing …
trace(reverse).
… then you can see what happens:
?- reverse([1,2,3],X,[]).
T Call: (7) reverse([1, 2, 3], _G1003, [])
T Call: (8) reverse([2, 3], _G1003, [1])
T Call: (9) reverse([3], _G1003, [2, 1])
T Call: (10) reverse([], _G1003, [3, 2, 1])
T Exit: (10) reverse([], [3, 2, 1], [3, 2, 1])
T Exit: (9) reverse([3], [3, 2, 1], [2, 1])
T Exit: (8) reverse([2, 3], [3, 2, 1], [1])
T Exit: (7) reverse([1, 2, 3], [3, 2, 1], [])
X = [3, 2, 1].
In your example the second rule builds the reversed list and the first rule "copies" the Reverse list to the Result variable.