Prolog problems {lists} - sorting

I'm having some problems in implementing code in prolog because I find it kind of hard to understand it since I'm habitual to normal coding :(
I have to sort a list of integers but it has to keep the duplicated values. I tried to think of a solution and I would use bubble sort but I don't know how to write it in prolog... If someone can explain the code step by step and to enlighten me I would really appreciate...
And yeah, another problem I have is to sort a list consisting of integers and lists of numbers... I have no idea how to start with this one... For example: [1, 2, [4, 1, 4], 3, 6, [7, 10, 1, 3, 9], 5, [1, 1, 1], 7] needs to output [1, 2, [1, 4, 4], 3, 6, [1, 3, 7, 9, 10], 5, [1, 1, 1], 7].
I tried to write some code but it doesn't work at all and I gave up... I copied something from the internet for the first problem but it doesn't really make sense for me...

Prolog is normal coding 🙃
It's just not imperative coding, and it's recursive by nature. You need to stop thinking in imperative terms (telling the compute what to do), and you need to start thinking recursively (A fine book on the topic.)
MergeSort is your friend here. It is a stable, recursive sorting algorithm that is performant and well-suited to the way prolog works. The way it works is easy:
The empty list is, by definition, ordered.
A list of length 1 is also, by definition, ordered.
For lists of length > 1,
partition the list into 2 halves,
recursively sort each one, and
merge the two now-ordered lists together.
That's all there is to it.
So, we need 3 things:
a predicate to partition a list into two halves,
a predicate to merge two ordered list into one ordered list, and
a predicate that orders a list, using those 2 helpers.
Partition
Partitioning a list is easy. There are two special cases that terminate the recursion, and one general case. The special cases are trivial:
The empty list ([]) is partitioned into 2 empty lists
partition( [] , [] , [] ) .
A list of length one is partitioned into itself and an empty list:
partition( [L] , [L] , [] ) .
The general case, that of a list of length greater than 1 is hardly more complex. Here, we just take the first 2 items from the list, assigning one to the left partition and the other to the right partition, and then we recurse down to process the remainder:
partition( [L,R|Xs] , [L|Ls] , [R|Rs] ) :- partition(Xs,Ls,Rs).
Putting it all together, you get partition/3:
partition( [] , [] , [] ) .
partition( [L] , [L] , [] ) .
partition( [L,R|Xs] , [L|Ls] , [R|Rs] ) :- partition(Xs,Ls,Rs) .
Merge
Merging 2 ordered lists into one ordered list is likewise simple. We have 3 special cases that terminate recursion, and one general case. The special cases are those where one source list is empty and the other is not, and the case of both source lists being the empty list:
merge( [] , [] , [] ) .
merge( [L|Ls] , [] , [L|Ls] ) .
merge( [] , [R|Rs] , [R|Rs] ) .
The general, recursive case, where the two source lists are non-empty is a little tricker (but not much). You have
the case where the left head collates before or equal to the right head, and
the case where the left head collates after the right head.
We can use Prolog's in-built operators for the comparison of terms to determine collation sequence:
merge( [L|Ls] , [R|Rs] , [L|Xs] ) :- L #=< R, merge( Ls , [R|Rs] , Xs ) .
merge( [L|Ls] , [R|Rs] , [R|Xs] ) :- L #> R, merge( [L|Ls] , Rs , Xs ) .
Putting it all together, you get merge/3:
merge( [] , [] , [] ) .
merge( [L|Ls] , [] , [L|Ls] ) .
merge( [] , [R|Rs] , [R|Rs] ) .
merge( [L|Ls] , [R|Rs] , [L|Xs] ) :- L #=< R, merge( Ls , [R|Rs] , Xs ) .
merge( [L|Ls] , [R|Rs] , [R|Xs] ) :- L #> R, merge( [L|Ls] , Rs , Xs ) .
Sort
And sorting is likewise easy. There are 2 special cases that terminate execution, the empty list and a list of length 1, both of which are ordered by definition. The general recursive case, for lists of length greater than 1 is
partition the list,
recursively sort each half, and
merge the two now-sorted lists
Thus:
merge_sort( [] , [] ) .
merge_sort( [X] , [X] ) .
merge_sort( [X,Y|Zs] , Ys ) :-
partition( [X,Y|Zs], L0, R0 ) ,
merge_sort(L0,Ls),
merge_sort(R0,Rs),
merge(Ls,Rs,Ys)
.
Whole Enchilada
You can fiddle with this at https://swish.swi-prolog.org/p/SCBlSONF.pl
partition( [] , [] , [] ) .
partition( [L] , [L] , [] ) .
partition( [L,R|Xs] , [L|Ls] , [R|Rs] ) :- partition(Xs,Ls,Rs) .
merge( [] , [] , [] ) .
merge( [L|Ls] , [] , [L|Ls] ) .
merge( [] , [R|Rs] , [R|Rs] ) .
merge( [L|Ls] , [R|Rs] , [L|Xs] ) :- L #=< R, merge( Ls , [R|Rs] , Xs ) .
merge( [L|Ls] , [R|Rs] , [R|Xs] ) :- L #> R, merge( [L|Ls] , Rs , Xs ) .
merge_sort( [] , [] ) .
merge_sort( [X] , [X] ) .
merge_sort( [X,Y|Zs] , Ys ) :-
partition( [X,Y|Zs], L0, R0 ) ,
merge_sort(L0,Ls),
merge_sort(R0,Rs),
merge(Ls,Rs,Ys)
.
You might notice that most of the work in this program consists of pattern matching in the heads of each predicate's clauses. That's a big part of what makes Prolog as expressive and concise as it is.

Related

Split a list into two lists of the same length

There is an initial list, split into two lists of the same length (ex. a list of 10 elements, split into 5 elements each), please, can anyone know with explanations desirable. Input: [1,2,3,4,5,6,7,8,9,10] Output: [1,2,3,4,5] [6,7,8,9,10] My beginnings:
len([],0).
len([X|L],N):-len(L,M),N is M+1.
?-len([1,2,3,4,5],X),write(X),nl.
%split([],[],[]).
%split([A],[A],[]).
%split([A|T],[A|T1],[B|T2]):-
% split(T,T1,T2).
%?-split([1,2,3,4,5,6],Lst1,Lst2),write(Lst1),write(Lst2),nl.
If the list item order doesn't matter to you, you might find the following split/3 congenial.
split([],[],[]).
split([X|Xs],[X|Ys],Zs) :-
split(Xs,Zs,Ys).
Sample queries using GNU Prolog 1.5.0:
| ?- split([a,b,c,d],Xs,Ys).
Xs = [a,c]
Ys = [b,d]
yes
| ?- split([a,b,c,d,e],Xs,Ys).
Xs = [a,c,e]
Ys = [b,d]
yes
If order doesn't matter, then just:
partition( [] , [] , [] ) .
partition( [Y] , [Y] , [] ) .
partition( [Y,Z|Xs] , [Y|Ys] , [Z|Zs] ) :- partition(Xs,Ys,Zs) .
If order is important, then the easiest way would be to simply
partition( Xs , Ys , Zs ) :-
length(Xs,N),
M is N div 2,
length(Ys,M),
append(Ys,Zs,Xs) .
[Though probably not what your instructor is looking for.]
Something like this would work:
partition( Xs , Ys, Zs ) :-
length(Xs,N0),
N is N0 div 2 ,
partition( N , Xs, Ys, Zs )
.
partition( 0 , Zs , [] , Zs ) .
partition( N , [X|Xs] , [X|Ys] , Zs ) :- N1 is N-1, partition(N1,Xs,Ys,Zs).
It runs in O(N) time — O(1.5N) actually. It traverses the source list once to determine its length, and then again to partition it.
As would this:
partition( Xs , Ys , Zs ) :- partition(Xs,Xs,Ys,Zs) .
partition( [] , Xs , [] , Xs ) .
partition( [_] , [X|Xs] , [X|Ys] , Xs ) .
partition( [_,_|Ts] , [X|Xs] , [X|Ys] , Zs ) :- partition(Ts,Xs,Ys,Zs ) .
Here you pass the source list to the helper predicate twice. From the one list, we strip two items on each iteration, and from the other, a single item. Once the list we're stripping two items from it exhausted, we're done.
This runs in O(N) time as well — O(N/2) actually, so it's somewhat more time efficient.

Find substrings of certain length

I'm a beginner at prolog and I'm having trouble getting started with the following problem:
Define the predicate partstr/3, where the first argument is a list, that generates a list A of length L that you find consecutive in the first list.
You should be able to present all answers with backtracking.
E.g.:
?- partstr([1, 2 , 3], L, A).
If L = 2 then A = [1,2] and [2,3],
or if L = 2 then F=[1,2] and [2,3].
and so on...
I feel like you would use recursion to solve it, but I'm not sure where to start. I would really appreciate some tips on how to solve this because I feel like I'm getting nowhere.
The core of this problem is that you need a way to pull all the sublist of length N from a list, correct?
So...
Consider that append/3 can concatenate two lists: append( [a,b,c], [1,2,3], L) returns L as [a,b,c,1,2,3]. But it can also decompose a list into a prefix and a suffix, so
append( Pfx, Sfx, [a,b,c])
will, on backtracking, successively yield:
Pfx
Sfx
[]
[a,b,c]
[a]
[b,c]
[a,b]
[c]
[a,b,c]
[]
...and... length/2 can not only tell you the length of a list, but
can generate lists of a specified length populated with unique,
unbound variables, so length(L,3) returns [V1,V2,V3].
You can combine those to get the behavior you want:
partstr( Xs, N, SL ) :- % To get all the contiguous sublists of length N from Xs...
append(_,Sfx,Xs) , % - repeatedly get all possible suffixes of Xs, and...
length(SL,N) , % - construct an empty, unbound list of the desired length (N), and...
append(SL,_,Sfx) % - pull that prefix off the suffix
. % Easy!
That's one approach. I imagine that this is coursework and that your instructor likely would like you to roll your own solution from scratch.
To do that, we first need a predicate that will yield the source list, and on backtracking remove the head of the list. Something like:
suffix( Xs , Xs ) .
suffix( [_|Xs] , Sfx ) :- suffix(Xs,Sfx).
Then we need a way to grab the 1st n elements from a list, something like this:
take( _ , 0 , [] ) :- ! .
take( [X|Xs] , N , [X|Sfx] ) :- N1 is N-1 , take(Xs,N1,Sfx) .
Given those two...
partstr( Xs, N , SL ) :-
suffix(Xs,Sfx),
take(Sfx,N, SL )
.
You can even dispense with the suffix/2 predicate, thus, rolling its functionality into partstr/3 itself:
partstr( Xs , N , SL ) :- take(Xs,N,SL).
partstr( [_|Xs] , N , SL ) :- partstr(Xs,N,SL).
And that, I think, is the sweet spot: it is hard to beat 4 lines of code —
partstr( Xs , N , SL ) :- take(Xs,N,SL) .
partstr( [_|Xs] , N , SL ) :- partstr(Xs,N,SL) .
take( _ , 0 , [] ) :- ! .
take( [X|Xs] , N , [X|Sfx] ) :- N > 0 , N1 is N-1 , take(Xs,N1,Sfx) .\

Partition a List in Prolog

This is the predicate:
partList(Len,L,R):-
length(L,LL),
length(R,RR),
RR is LL/Len,
append(R,L).
The query shows:
42 ?- partList(2,[t,t,t,f,f,t,f,f],R).
R = [[], [], [], [t, t, t, f, f, t, f, f]] .
But I want to partition into
[[t,t],[t,f],[f,t],[f,f]].
How do I fix this? Thanks!
The easy way is to look at the problem are repeatedly stripping off the 1st N items from the head of the list (until the list is exhausted).
partition( [] , [] ) . % if the source list is exhausted, we're done.
partition( [X] , [X] ) . % if the source list contains just one item, we're done.
partition( [X,Y|Z] , [[X,Y]|R] ) :- % if the source list contains 2 or more items, we take the 1st two, and ...
partition(Z,R) % - recursively partition the remainder.
. % Easy!.
To make it generic isn't much more complex.
First, we need a way to partition the list into a prefix, containing N items (or fewer if the list isn't sufficiently long) and a suffix, containing whatever's left (which might be nothing):
take_prefix( _ , [] , [] , [] ) . % if the source list is empty, both prefix and suffix are empty, regardless of the value of N.
take_prefix( 0 , [X|Xs] , [] , [X|Xs] ) . % if N is 0, The prefix is the empty list and the suffix is the source list.
take_prefix( N , [X|Xs] , [X|P] , S ) :- % otherwise, add the head to the prefix,
N > 0 , % - assuming N > 0
N1 is N-1 , % - decrement N
take_prefix(N1,Xs,P,S) % - and recurse down.
. % Easy!
This is the crux of the matter. Once you have that, it's just a matter of repeatedly (and recursively) applying it until you get to the empty list:
partition( _ , [] , [] ) . % if the source list is empty, we're done.
partition( N , L , [P|R] ) :- % otherwise...
take_prefix(N,L,P,S) , % - break it up into a prefix and a suffix,
partition(N,S,R) % - and recurse down on the suffix.
. % Easy!

Prolog program to reverse and append the list

I am new to prolog. I am trying to reverse the order of list and append them.
For example :
revappend([1,2], [3,4], X) Should give me result like :
X = [3,4,1,2]
The code I wrote :
revappend([],List,List).
revappend(InputListB,[Head|InputListA], [Head|OutputList]):-
revappend( InputListA, InputListB, OutputList).
Giving me result like :
X = [15, 11, 16, 12, 13, 14]
Can someone tell me how to do this??
you want to reverse the order of list and append them or more precisely you want to append second list with the first list and here is prolog rule to do the same.
append(List,[],List).
append(List,[Head|Tail],[Head|Res]):-append(List,Tail,Res).
The 1st rule says that when the 2nd list is empty you gonna append the first list to the result.
The second rule says that you gonna add head of the second list to the result and recursively append the tail of the second list with the first list.
The problem statement is unclear to me. If what you want is to have
revappend( [1,2] , [3,4] , L ) .
produce, as your example shows:
L = [3,4,1,2]
the solution is easy:
revappend( Xs , Ys , Zs ) :- append(Ys,Xs,Zs) .
If you don't want to, or can't use, the built-in append/3, you might do something like:
revappend( [] , [] , [] ) .
revappend( Xs , [Y|Ys] , [Y|Zs] ) :- revappend( Xs , Ys , Zs ) .
revappend( [X|Xs] , [] , [X|Zs] ) :- revappend( Xs , [] , Zs ) .
However, when I hear something like your problem statement, though:
I am trying to reverse the order of list and append them.
I would expect that your
revappend( [1,2] , [3,4] , L ) .
would produce either L = [2,1,4,3] or L = [4,3,2,1].
For the former ([2,1,4,3]) case, you might write something like this:
revappend( Xs, Yz , Zs ) :- revappend(Xs,Yz,[],Zs) .
revappend( [] , [] , Zs , Zs ) .
revappend( [X|Xs] , Ys , Rs , Zs ) :- revappend(Xs,Ys,[X|Rs],Zs).
revappend( [] , [Y|Ys] , Rs , Zs ) :- revappend([],Ys,[Y|Rs],Zs).
For the latter ([4,3,2,1]), you just need to change things up a bit, modifying revappend/4 along these lines:
revappend( [] , [] , Zs , Zs ) .
revappend( Xs , [Y|Ys] , Rs , Zs ) :- revappend(Xs,Ys,[Y|Rs],Zs).
revappend( [X|Xs] , [] , Rs , Zs ) :- revappend(Xs,[],[X|Rs],Zs).
Note that you can do this with built-ins as well:
revappend(Xs,Ys,Zs) :-
reverse(Xs,X1) ,
reverse(Ys,Y1) ,
append(X1,Y1,Zs)
.

Remove the element in list

I want to remove the element in list1 when it is equal to element in list2.
The query and the expected output is:
filter( [[1,2,3],[1]] , [[1]] , X ).
X = [[1, 2, 3]] ;
filter( [[1,2,3],[1],[2,3,4],[2]] , [[1],[2]] , X ).
X = [[1, 2, 3],[2,3,4]] ;
What I have done right now is :
filter(_,[],_).
filter([A|B],[A|D],E):-
filter(B,D,E).
filter([A|B],[C|D],[A|E]):-
A\=C,
filter(B,D,E).
but it seems not right and gives the output like this:
11 ?- filter([[1,2,3],[1]],[[1]],X).
X = [[1, 2, 3]|_G488] ;
Can anyone help? Maybe I was near success.
Your program will not work correctly because you are removing one element from the second list each time. Also your base case (the first clause) should not be an uninstantiated variable (that is what is giving you the |_G488 in your output.
You have to iterate over the first list filtering the elements found in the second list, but not remove the elements of the second list.
For example:
filter([], _, []).
filter([Item|L1], L2, L3):-
(member(Item, L2) -> L4=L3;L3=[Item|L4]),
filter(L1, L2, L4).
The first clase is the base case of the recursion. It states that the output for an empty list would be an empty list.
The second clause checks to see if the first item of the input list is found on the second list. If it is found then it won't be added to the resulting list; otherwise it is added. Then it recursively calls itself with the rest of the input list.
But in no case it removes the elements from the second list.
Well, the lazy way would be to use the build-ins, findall/3 and member/2:
filter( Xs , Ys , Rs ) :-
findall( X , ( member(X,Xs), \+ member(X,Ys) ) , Rs ) .
which says to find all X such that X is a member of the list Xs and Xs is *not* a member of the listYs`.
Assuming your instructor wants you to come up with your own implementation, you probably first want to decompose your problem. You need to do two things:
Iterate over a list, removing items that are found in another list.
Given an item, determine whether it is contained in another list.
Both of these are simple. To determine if an item is contained in a list, you could say something like:
contained_in( X , [X|Ys] ) :- % if we find the item in the list,
! . % - we succeed and eliminate any alternatives.
contained_in( X , [_|Ys] ) :- % otherwise, we discard the head of the list,
contained_in(X,Ys) . % - and keep looking by recursing down.
The actual filtering is pretty simple, too:
filter( [] , _ , [] ) . % once the source list is exhausted, we're done.
filter( [X|Xs] , Ys , [X|R] ) :- % otherwise...
\+ contained_in(X,Ys) , % - if the current list item is not contained in the list of items to be removed,
! , % - cut off alternatives,
filter( Xs , Ys , R ) . % - add the current item to the result list and recurse down.
. %
filter( [_|Xs] , Ys , R ) :- % if the current list item IS contained in the list of items to be removed,
filter(Xs , Ys , R ) % - discard it and recurse down.
. % Easy!
Your filter is just subtract available with many Prolog systems (I've tested with B-Prolog, SWI-Prolog and ECLiPSe):
?- subtract( [[1,2,3],[1]] , [[1]] , X ).
X = [[1, 2, 3]].
?- subtract( [[1,2,3],[1],[2,3,4],[2]] , [[1],[2]] , X ).
X = [[1, 2, 3], [2, 3, 4]].
You can look at the sources of SWI-Prolog or ECLiPSe for implementation details.

Resources