Prolog add elements - prolog

My problem is:
Write a Prolog program that, given two lists L1 and L2
, outputs
two new lists L3 and L4
such that L3 contains the elements of
L1 which also belong to L2
, while L4 contains the elements
of L1 which do not belong to L2
. You may use the built-in
predicate member.
As an example, the query listmem([a, r, t], [t, s, m, n, a], L3, L4)
produces L3 = [a, t] and L4 = [r].
And my solution is now:
memberOf([], [], _).
memberOf([H|T], L2, [X|Xs]) :-
X is H,
member(X, L2),
memberOf(T, L2, Xs).
But when I test on the following input, it returns no..
memberOf( [1,2,3], [2,3,4], L3 ).
What am I doing wrong?

listmem(L1,[],[],L1).
listmem([],_,[],[]).
listmem([H1|T1],L2,[H1|L3],L4):-
member(H1,L2), !,
listmem(T1,L2,L3,L4).
listmem([H1|T1],L2,L3,[H1|L4]):-
listmem(T1,L2,L3,L4).
I've added a cut to the third case instead of a \+ member(H1,L2) to the last one so you can use listmem the "other way around", e.g., instead of:
?- listmem([a, r, t], [t, s, m, n, a], L3, L4).
L3 = [a, t],
L4 = [r].
You can also:
?- listmem([a, r, t], L2, [a,t], L4).
L2 = [a, t|_G10554000],
L4 = [r].

Related

Separating list of facts in prolog

I have a list of facts in Prolog.
Say:
L = [mother(sue), father(sam), mother(rachel), mother(izzie), father(leo)]
I want to separate them into two lists
L1 = [mother(sue), mother(rachel), mother(izzie)]
L2 = [father(sam), father(leo)]
How do I do that in Prolog
I hope I'm not doing your homework for you, but here it is:
split([], [], []).
split([mother(X)|L], [mother(X)|L1], L2) :- split(L, L1, L2).
split([father(X)|L], L1, [father(X)|L2]) :- split(L, L1, L2).
Usage:
?- split([mother(sue), father(sam), mother(rachel), mother(izzie), father(leo)], L1, L2).
L1 = [mother(sue), mother(rachel), mother(izzie)],
L2 = [father(sam), father(leo)]

How to shuffle lists in Prolog while preserving inner order

I'm trying to print out all possible shuffled variants of two lists in one list while preserving the order.
I need to write a predicate shuffle(L1, L2, L3) which shuffles L1 and L2 and puts the result into L3 while preserving the inner order of L1 and L2.
For example :
?- shuffle([a,b],[1,2],L).
L = [a,b,1,2] ;
L = [a,1,b,2] ;
L = [a,1,2,b] ;
L = [1,a,b,2] ;
L = [1,a,2,b] ;
L = [1,2,a,b]
What I have so far :
shuffle([],[],[]).
shuffle([X|Xs],[Y|Ys],[X,Y|Tail]) :-
shuffle(Xs,Ys,Tail).
shuffle([X|Xs],[Y|Ys],[Y,X|Tail]) :-
shuffle(Xs,Ys,Tail).
This results in :
| ?- shuffle([a,b],[1,2],L).
L = [a,1,b,2] ? ;
L = [a,1,2,b] ? ;
L = [1,a,b,2] ? ;
L = [1,a,2,b]
So I'm missing the cases of "simple append" of L1+L2 and L2+L1...
What is my predicate missing?
We can use dcg for its ease of writing:
shuffle([A|B],[C|D]) --> [A] , shuffle(B,[C|D]).
shuffle([A|B],[C|D]) --> [C] , shuffle([A|B],D).
shuffle(A,[]) --> A.
shuffle([],C) --> C.
shuffle( A, B, C) :- phrase( shuffle(A,B), C).
We either take first card from one non-empty deck or the other, but if one of them is empty we must use all the remaining cards in the non-empty deck at once.
Unfortunately this leaves one extra choice point at the end:
5 ?- shuffle([a,b],[1,2],C).
C = [a, b, 1, 2] ;
C = [a, 1, b, 2] ;
C = [a, 1, 2, b] ;
C = [1, a, b, 2] ;
C = [1, a, 2, b] ;
C = [1, 2, a, b] ;
false.
As for your approach the problem with it was that you tried to take care of two cards at once, and it got complicated. Going by smallest steps can be the easiest.
Here's how you can shuffle two lists while preserving the relative item order.
shuffle([], Xs, Xs).
shuffle([X|Xs], Ys, Zs) :-
shuffle_(Ys, X, Xs, Zs). % use auxiliary predicate shuffle_/4
shuffle_([], X, Xs, [X|Xs]). % do indexing on both lists
shuffle_([Y|Ys], X, Xs, [X|Zs]) :-
shuffle_(Xs, Y, Ys, Zs).
shuffle_([Y|Ys], X, Xs, [Y|Zs]) :-
shuffle_(Ys, X, Xs, Zs).
Sample query using SWI-Prolog:
?- shuffle([a,b], [1,2], Xs).
Xs = [a,1,b,2]
; Xs = [a,1,2,b]
; Xs = [a,b,1,2]
; Xs = [1,a,2,b]
; Xs = [1,a,b,2]
; Xs = [1,2,a,b]. % no useless choice point at the end
#repeat's answer is more elegant and efficient, but, as an alternative:
The unwanted choice-point can be removed using a reusable empty_list_first predicate:
shuffle([A|B], [C|D]) --> [A],
shuffle(B, [C|D]).
shuffle([A|B], [C|D]) --> [C],
{ empty_list_first([A|B], D, A1, D1) },
shuffle(A1, D1).
% Rewritten to prevent needing https://www.swi-prolog.org/pldoc/man?section=basics
%shuffle([], C) --> remainder(C).
shuffle([], C, C, []).
shuffle(A, B, C) :-
empty_list_first(A, B, A1, B1),
phrase(shuffle(A1, B1), C).
empty_list_first([], L2, [], L2).
empty_list_first([H|T], L2, EL1, EL2) :-
empty_list_first_(L2, [H|T], EL1, EL2).
empty_list_first_([], L1, [], L1).
% If neither are empty, keep original order
empty_list_first_([H|T], L1, L1, [H|T]).
Result in swi-prolog:
?- shuffle([a,b], [1,2], C).
C = [a,b,1,2] ;
C = [a,1,b,2] ;
C = [a,1,2,b] ;
C = [1,a,b,2] ;
C = [1,a,2,b] ;
C = [1,2,a,b].
My answer is posted long time after original question but hoping this might prove useful to someone some day. I've taken a different approach to this, might be on the longer side but it works... :)
Since one of the requirements at the class I'm taking to not exceed material learned, some items such as delete and concatenate have been created here as well.
del(X,[X|Xs],Xs).
del(X,[Y|Ys],[Y|Zs]):-
del(X,Ys,Zs).
permutation([],[]).
permutation(Xs,[Z|Zs]):-
del(Z,Xs,Ys),
permutation(Ys,Zs).
conc([],L,L).
conc([X|L1],L2,[X|L3]):-
conc(L1,L2,L3).
is_in_order([],_).
is_in_order([_],_).
is_in_order(Sublist1, Sublist2, Superlist) :-
remove_elements(Superlist, Sublist1, SuperSubList),
list_equal(Sublist2, SuperSubList).
list_equal([], []).
list_equal([X|Xs],[X|Ys]) :-
list_equal(Xs, Ys).
% Remove L1 from L2 and return the resulting list
remove_elements(L, [H|T], R) :-
delete(L, H, R1),
remove_elements(R1, T, R).
remove_elements(L, [], L).
/*Shuffle first creates a concatenated list from both L1 & L2
* It then create permutation for all possible combinations of L1 & L2
* Once done, it scrubs the new lists to filter out the ones that do not
* maintain the original order of L1 & L2
* The result is only the permutations that fullfills the order condition
*/
shuffle(L1,L2,L):-
conc(L1,L2,L3),
permutation(L3, L),
is_in_order(L1, L2, L),
is_in_order(L2, L1, L).

Splitting a list into 2 lists at a pivot in prolog

I want to split a list into 2 lists at a pivot P, if the number is less than P it goes into L1 and if it is greater than P then it will go into L2.
This is what I have so far, I am able to split a list L into L1 = [[],[]] in this form. But I want to split the list into 2 lists L1, and L2, how would I do that?
split(L,P,L1):-
split(L,P,[],L1).
split([],_,[],[]).
split([],_,X,[X]) :- X \= [].
split([P|T],P,[],L1) :- split(T,P,[],L1).
split([P|T],P,L,[L|L1]) :- L \= [], split(T,P,[],L1).
split([H|T],P,S,L1) :- H \= P, append(S, [H], S2), split(T,P,S2,L1).
You only need three rules to implement this predicate:
:- use_module(library(clpfd)).
split([], _, [], []).
split([H|T], P, L1, [H|T2]) :-
H #>= P,
split(T, P, L1, T2).
split([H|T], P, [H|T1], L2) :-
H #< P,
split(T, P, T1, L2).
The code is fairly straightforward
Note that, because of library(clpfd), this predicate also works e.g. when the initial list and the pivot are not known:
?- split(L,P,[5,47],[101]).
L = [101, 5, 47],
P in 48..101 ;
L = [5, 101, 47],
P in 48..101 ;
L = [5, 47, 101],
P in 48..101 ;
false.
Using partition/4
As mentionned in a comment, you can use partition/4 to do this:
split(L, P, L1, L2) :-
partition(zcompare(>,P), L, L1, L2).
However, this will not exhibit as many different behaviours as the first implementation.

Getting the head and tail of a list

I know if I do:
[H|T] = [a,b,c,d].
H = a,
T = [b,c,d].
What I'm trying to do is get the head and tail of a list inside a rule. Is this possible? I'm setting up base cases for a recursive call but for now I'd be satisfied if it just returned L3 as a append of the first list head and the second list head. I'm just not sure how I can get the head and list.
compose([], L1, L1).
compose(L2, [], L2).
compose([], [], []).
compose(L1, L2, L3) :-
[H1|T1] = L1,
[H2|T2] = L2,
append(H1, H2, L3).
I've also tried doing below based on what I've seen online:
compose([], L1, L1).
compose(L2, [], L2).
compose([], [], []).
compose([H1|T1], [H2|T2], L3) :-
append(H1, H2, L3).
but the trace fails on the Call to this predicate.In a successful case I would like it to do the following:
compose([a,b,c], [d,e,f], L).
L = [a, d].
at the very least for now.
compose([X|_],[Y|_], [X,Y]).
It is not more than that. Maybe you want to add cases for empty lists:
compose([], [], []).
compose([X|_], [], [X]).
compose([], [X|_], [X]).

Prolog variable gets no value

I've written the following code in prolog:
contains(L1, []).
contains(L1, [X | T2]) :- member(X, L1), contains(L1, T2).
minus(L, [], L).
minus(L1, L2, L3) :- contains(L1, L3), nomembers(L3, L2).
nomembers(L1, []).
nomembers(L1, [X | T2]) :- not(member(X, L1)), nomembers(L1, T2).
contains(L1, L2) returns true if all of the members in L2 appear in L1. (contains([1,2],[1,1,1]) is true).
minus(L1, L2, L3) returns true if L3=L1\L2, meaning L3 consists of members of L1 but not of L2.
When I ask minus([1,2,3,4],[2,1],L), I get the answer that L=[], although logically it should be L=[3,4]. Does someone know why?
Above comment of mbratch is very helpful.
Notice, that your current minus(L1, L2, L3) definition is: All members of L3 are in L1 and no member from L3 is in L2.
Prolog is giving you good answer with L3 = [], it fits for definition I wrote above.
EDIT: Below code should do what you want, but currently I don't have prolog on my computer, so I can't test it.
remove(X, [X|T], T) :- !.
remove(X, [H|T], [H|T2]) :- remove(X, T, T2).
minus(L1,[],L1).
minus(L1,[H|T2],T3) :- member(H, L1), !, remove(H,L1,L4), minus(L4, T2, T3).
minus(L1,[H|T2],[H|T3]) :- minus(L1, T2, T3).
remove(X,LA,LB) which says: LB is LA without it first occurrence of X, so it's just removing element from the list.

Resources