Prefix in Prolog - list

I'm new in Prolog.
I have a problem about predicate prefix but a little bit different.
I want to get a prefix of a list but until an element
The list can have repeat elements.
An example:
prefix(Element, List, Prefix)
prefix(c, [a,b,c,d,e,f], [a, b])
The element is not included.
What I have so far is this
prefix(X, [X|T], []).
prefix(X, [Y|T], [Y|Z]):-
prefix(X, T, Z).
But it does not work.
L = [a,b,c] ? prefix(b, L, Prefix).
no
?-
Thanks

With dif/2 you can explicitly state that for any member X preceding Element, X \== Element:
prefix(Element, [Element|_], []).
prefix(Element, [Head|List], [Head|Prefix]) :-
dif(Element, Head),
prefix(Element, List, Prefix).
or equally, because I wanted to use append/3 in the first iteration of my answer:
prefix(Element, List, Prefix) :-
append(Prefix, [Element|_Suffix], List),
maplist(dif(Element), Prefix).
For the suffix it is basically the same:
suffix(Element, List, Suffix) :-
append(_Prefix, [Element|Suffix], List),
maplist(dif(Element), Suffix).
If you don't want to use maplist(dif(Element), List):
all_dif(_, []).
all_dif(X, [H|T]) :- dif(X, H), all_dif(X, T).

Here is a solution using Definite Clause Grammars dcg and the non-terminal all_seq//2:
prefix(X, Xs, Ys) :-
phrase( ( all_seq(dif(X), Ys), [X], ... ), Xs).
... --> [] | [_], ... .
So the grammar (within phrase/2) reads:
There is
1. an initial sequence Ys with all elements different to X, followed by 2. X, followed by 3. anything.
There is still a downside, which is often the case when using DCGs: The implementation is not as determinate as it could be and thus leaves superfluous choicepoints around.

prefix(X,[X|T],[]).
prefix(X,[Y|T],Z) :- prefix(X,T,M) , Z = [Y|M].
output:
?- L = [a,b,c,d,e,f] , prefix(d,L,G). L = [a, b, c, d, e, f], G = [a,
b, c] .
?- L = [a,b,c,d,e,f] , prefix(e,L,G). L = [a, b, c, d, e, f], G = [a,
b, c, d] .
EDIT #1
the original code is working , use (,) instead of (?) as following.
prefix(X,[X|T],[]).
prefix(X,[Y|T],[Y|Z]) :- prefix(X,T,Z).
output:
?- prefix(d , [a,b,c,d,e] , G). G = [a, b, c]
?- L = [a,b,c] , prefix(b, L, Prefix).
L = [a, b, c],
Prefix = [a] .
EDIT #2
as user false mentioned in comment, I can confirm that you are right, but in my solution, I assume that the list contains unique elements:
prefix(d,[d,d],[d]) succeeds - it should fail ,

Related

Trying to Implement a Split Predicate in Prolog

I am trying to implement a partition predicate in Prolog that splits a list into its two halves, a Prefix and a Suffix, of approximately same lengths.
partition(L,P,S)
Where prefixes and suffixes are defined as such:
prefix(P,L) :- append(P,_,L).
suffix(S,L) :- append(_,S,L).
If L is [], then Prefix and S are [].
If L is [H], then P is [H] and S is [].
If L has two or more elements, this is how the list is partitioned into its prefix and suffix:
Length of L is N and the length of P is div(N,2). The length of S is N - div(N,2).
So for instance:
?- partition([a,b,c,d],X,Y).
X = [a,b]
Y = [c,d]
?- partition([a],X,Y).
X = [a]
Y = [ ]
Here is my code and the error I get:
partition([],[],[]).
partition([H],[H],[]).
partition(L, P, S) :-
length(L, N),
Plen is div(N,2),
Slen is N - div(N,2),
length(Pre, Plen),
length(Suff, Slen),
prefix(Pre, L),
suffix(Suff, L),
P is Pre,
S is Suff.
partition([a,b,c,d],X,Y).
>>> Type error: `[]' expected, found `[a,b]' (a list)
("x" must hold one character)
I don't understand this error message but this is wrong:
P is Pre,
S is Suff.
This is for arithmetic evaluation whereby the Right-Hand-Side is evaluated as an arithmetic expression and unified with the Left-Hand-Side.
You just want to unify the variables:
P = Pre,
S = Suff.
Alternatively, you can use the same same for P and Pre / S and Suff throughout.
If you change is to to = as suggested by David Tonhofer's answer, the whole thing works.
But I would like to add that you are complicating things a bit. You have identified correctly that append/3 can be used to compute list prefixes and suffixes. But for any list to be partitioned and any prefix, the suffix is unique, and is already computed by append/3! And the other way round: If you ask it to compute a suffix, it will also compute the prefix you seek. But then you throw these answers away and try to recompute a matching prefix or suffix. There is no need to do that.
If we make your prefix and suffix predicates a bit more explicit:
list_prefix_theonlypossiblematchingsuffix(List, Prefix, TheOnlyPossibleMatchingSuffix) :-
append(Prefix, TheOnlyPossibleMatchingSuffix, List).
list_suffix_theonlypossiblematchingprefix(List, Suffix, TheOnlyPossibleMatchingPrefix) :-
append(TheOnlyPossibleMatchingPrefix, Suffix, List).
We can see that once we have a given prefix for a list, there really is no more choice for the suffix (and vice versa):
?- list_prefix_theonlypossiblematchingsuffix([a, b, c, d], Prefix, MatchingSuffix).
Prefix = [],
MatchingSuffix = [a, b, c, d] ;
Prefix = [a],
MatchingSuffix = [b, c, d] ;
Prefix = [a, b],
MatchingSuffix = [c, d] ;
Prefix = [a, b, c],
MatchingSuffix = [d] ;
Prefix = [a, b, c, d],
MatchingSuffix = [] ;
false.
So there is no need to try to compute the prefix and suffix separately and to match up their lengths. It's enough to restrict the prefix, as the suffix will follow:
partition(List, Prefix, TheOnlyPossibleMatchingSuffix) :-
length(List, N),
PrefixLength is N div 2,
length(Prefix, PrefixLength),
list_prefix_theonlypossiblematchingsuffix(List, Prefix, TheOnlyPossibleMatchingSuffix).
This works as you want:
?- partition([a, b, c, d], Prefix, Suffix).
Prefix = [a, b],
Suffix = [c, d].
?- partition([a, b, c, d, e], Prefix, Suffix).
Prefix = [a, b],
Suffix = [c, d, e].
Once you have this, it's much clearer to replace the goal involving list_prefix_verylongpredicatename with what is really meant:
partition(List, Prefix, Suffix) :-
length(List, N),
PrefixLength is N div 2,
length(Prefix, PrefixLength),
append(Prefix, Suffix, List).
Coming from other programming languages it may be a bit unusual that a predicate like append/3 computes several things at once that have a deep relationship with each other, i.e., a prefix and the unique matching suffix. But this is one of the things that makes Prolog so expressive and powerful. Get used to it and profit from it!
It seems to me that you're doing a lot of unnecessary work here.
This is all I think you need:
partition(L,P,S) :-
partition(L,L,P,S).
partition(L,[],[],L).
partition(([H|L],[_],[H],L).
partition([H|L],[_,_|L2],[H|P],S) :-
partition(L,L2,P,S).
If I query ?- partition([a],X,Y), write([X,Y]). then I get:
[[a], []]
true.
If I query ?- partition([a,b,c,d,e],X,Y), write([X,Y]). then I get:
[[a, b, c], [d, e]]
true.
Since you've already defined your prefixes and suffixes as
prefix(P,L) :- append(P, _, L). % prefix
suffix(S,L) :- append(_, S, L). % suffix
just smash the two together into one call,
partition(L,P,S) :-
append(P, S, L),
and this would be it, except you have additional conditions about the comparative lengths of the two near-halves, so just add them into the mix:
length( P, N), length( A, N), % same length, fresh list A
(A = [_|S] ; A = S). % S one shorter than P, or same length
And that's that. Testing:
2 ?- partition( [1,2,3], A, B ).
A = [1, 2],
B = [3].
3 ?- partition( L, [1,2], [3] ).
L = [1, 2, 3].
15 ?- partition( L, A, B ).
L = A, A = B, B = [] ;
L = A, A = [_G2477],
B = [] ;
L = [_G2477, _G2483],
A = [_G2477],
B = [_G2483] ;
L = [_G2477, _G2483, _G2492],
A = [_G2477, _G2483],
B = [_G2492] ;
L = [_G2477, _G2483, _G2489, _G2492],
A = [_G2477, _G2483],
B = [_G2489, _G2492]
....

Sublists of consecutive similar elements from a list in Prolog

I'm new to Prolog and trying to do this question. We have a list
List = [a,a,a,a,b,c,c,a,a,d,e,e,e,e]
I want to pack it into sub-lists of similar elements.
Pack( [a,a,a,a,b,c,c,a,a,d,e,e,e,e], Sublists)
should give
Sublists = [[a,a,a,a],[b],[c,c],[a,a],[d],[e,e,e,e]]
This is what I have tried so far:
pack([],[],[]).
pack([H],[H],[H]).
pack([H,H1|T],Z,X):- H==H1 , append([H],Z,Z1) , pack([H1|T],Z1,X).
pack([H,H1|T],Z,X):- H=\=H1 , append([H],Z,Z1) ,
append(Z1,X,Xs) , pack([H1|T],Z1,Xs).
Below is the error:
Arithmetic: `a/0' is not a function
In:
[4] a=\=b
[3] pack([a,b|...],[a,a],_1608) at line 13
[2] pack([a,a|...],[a],_1688) at line 13
[1] pack([a,a|...],[],_1762) at line 13
Thanks in advance. I'm trying to solve these problems:
P-99: Ninety-Nine Prolog Problems.
You can approach this kind of problem with simple list processing and using SWI Prolog's dif/2 to provide a general solution:
pack([], []). % packing empty is empty
pack([X], [[X]]). % packing a single element
pack([X,X|T], [[X|PH]|PT]):- % rule for packing when next two terms are the same
pack([X|T], [PH|PT]).
pack([X,Y|T], [[X]|PT]):- % rule for different term
dif(X, Y),
pack([Y|T], PT).
2 ?- pack([a,a,a,a,b,c,c,a,a,d,e,e], L).
L = [[a, a, a, a], [b], [c, c], [a, a], [d], [e, e]] ;
false.
3 ?- pack(L, [[a,a,a], [b,b], [c]]).
L = [a, a, a, b, b, c] ;
false.
4 ?-
Note that lurker's solution still has some performance issues. See the ; false for each solution? This is an indication that Prolog still retains some memory (called a choice point - actually there may be even several such choice points). For many cases however, no such choice point is needed. Here is a solution that overcomes that problem (The name group in place of pack is quite common in the context of Haskell)
group([], []).
group([E|Es], [[E|Gs]|Gss]) :-
igroup(Es, E, Gs, Gss).
igroup([], _, [], []).
igroup([E|Es], F, Gs1, Gss1) :-
( E\=F
-> Gs1=[], Gss1=[[E|Gs2]|Gss2]
; E==F
-> Gs1=[E|Gs2], Gss1=Gss2
; E=F,
Gs1=[E|Gs2], Gss1=Gss2
; dif(E, F),
Gs1=[], Gss1=[[E|Gs2]|Gss2]
),
igroup(Es, E, Gs2, Gss2).
Note how the testing for the equality of E and F is split into four cases:
First E \= F which means that both are definitely different.
Then E == F which means that both are definitely identical.
Then E = F which is the general case of equality, and
dif(E, F) which is the case of general inequality
For the last two cases there is no -> because both may be true.
Since it is quite cumbersome to maintain so many cases, there is library(reif)
for
SICStus and
SWI which permits to write the same more compactly:
igroup([], _, [], []).
igroup([E|Es], F, Gs1, Gss1) :-
if_(E = F
, ( Gs1 = [E|Gs2], Gss1 = Gss2 )
, ( Gs1 = [], Gss1 = [[E|Gs2]| Gss2] )),
igroup(Es, E, Gs2, Gss2).
The error you got is because =\=/2 is true if expr1 is evaluates to a number not equal to expr2 . Instead you can use \=\2 which evaluates \+term1=term2. ==/2 evaluates to term1 equivalent to term2, =:=/ is true if expr1 is a number which is equal to expr2. One more mistake I found in your code is you're not clearing the Intermediate List. You have to flush the values in it after you have added the similar elements list to your Sublists list. I have used cut ! to reduce backtracking. Instead, if you write mutually exclusive predicates, it's better.
I have edited your code:
pack1([],[],[]).
pack1([H],L,[Z]):- append([H],L,Z),!.
pack1([H,H1|T],Z,X):- H == H1 , append([H],Z,Z1) , pack1([H1|T],Z1,X),!.
pack1([H,H1|T],Z,[Z1|Zs]):- H\=H1 ,append([H],Z,Z1) ,pack1([H1|T],[],Zs),!.
Output:
?-pack1([a,a,a,a,b,c,c,a,a,d,e,e,e,e],[],Z).
Z=[[a, a, a, a], [b], [c, c], [a, a], [d], [e, e, e, e]]
?-pack1([a,a,a,a,b,c,1,c,a,a,d,e,e,e,e],[],Z).
Z= [[a, a, a, a], [b], [c], [1], [c], [a, a], [d], [e, e, e, e]]
?-pack1([],[],Z).
Z= []
Hope this helps.
without using dif/2
my_pack([],[[]]).
my_pack([X], [[X]]).
my_pack([X,X|L], [F|R]) :- my_pack([X|L], [F1|R]), append([X], F1, F).
my_pack([X|L], [F|R]) :- my_pack(L, R), append([X], [], F).

Include non-unique elements only

This question was asked but there are no answers: here. I read the comments and tried to implement in both ways, but there are more problems that I don't understand.
I first tried the easy way that doesn't keep original order:
list_repeated(L, Ds) :-
msort(L, S),
sorted_repeated(S, Ds).
sorted_repeated([], []).
sorted_repeated([X|Xs], Ds) :-
first(Xs, X, Ds).
first([], _, []).
first([X|Xs], X, [X|Ds]) :-
more(Xs, X, Ds).
first([X|Xs], Y, Ds) :-
dif(X, Y),
first(Xs, X, Ds).
more([], _, []).
more([X|Xs], X, Ds) :-
more(Xs, X, Ds).
more([X|Xs], Y, Ds) :-
dif(X, Y),
first(Xs, X, Ds).
Once the list is sorted without removing duplicates, using first and more I add the element to the second argument if it occurs at least twice and skip all consecutive copies of the element.
This is not working properly because if I have:
?- list_duplicates([b,a,a,a,b,b], Ds).
I get answer [a,b] instead of [b,a] and also I get ; false after the answer.
I also tried another way, but this doesn't work because the accumulator is immutable?
list_duplicates(L, Ds) :-
ld_acc(L, [], Ds).
ld_acc([], _, []).
ld_acc([X|Xs], Acc, Ds) :-
( memberchk(X, Acc)
-> Ds = [X|Ds0],
ld_acc(Xs, Acc, Ds0)
; Acc1 = [X|Acc],
ld_acc(Xs, Acc1, Ds)
).
This cannot work because when I check that an element is member of accumulator I remove only one occurrence of each element: if I have three times the same element in the first argument, I am left with two. If I could change the element in the accumulator then I could maybe put a counter on it? In the first version I used different states, first and more, but here I have to attach state to the elements of the accumulator, is that possible?
A plea for purity
When programming in Prolog, a major attraction is the generality we enjoy from pure relations.
This lets us use our code in multiple directions, and reason declaratively over our programs and answers.
You can enjoy these benefits if you keep your programs pure.
Possible solution
As always when describing lists, also consider using DCG notation. See dcg for more information.
For example, to describe the list of duplicates in a pure way, consider:
list_duplicates([]) --> [].
list_duplicates([L|Ls]) -->
list_duplicates_(Ls, L),
list_duplicates(Ls).
list_duplicates_([], _) --> [].
list_duplicates_([L0|Ls], L) -->
if_(L0=L, [L], []),
list_duplicates_(Ls, L).
This uses if_//3 to retain generality and determinism (if applicable).
Examples
Here are a few example queries and answers. We start with simple ground cases:
?- phrase(list_duplicates([a,b,c]), Ds).
Ds = [].
?- phrase(list_duplicates([a,b,a]), Ds).
Ds = [a].
Even the most impure version will be able to handle these situations correctly. So, slightly more interesting:
?- phrase(list_duplicates([a,b,X]), Ds).
X = a,
Ds = [a] ;
X = b,
Ds = [b] ;
Ds = [],
dif(X, b),
dif(X, a).
Pretty nice, isn't it? The last part says: Ds = [] is a solution if X is different from b and a. Note the pure relation dif/2 automatically appears in these residual goals and retains the relation's generality.
Here is an example with two variables:
?- phrase(list_duplicates([X,Y]), Ds).
X = Y,
Ds = [Y] ;
Ds = [],
dif(Y, X).
Finally, consider using iterative deepening to fairly enumerate answers for lists of arbitrary length:
?- length(Ls, _), phrase(list_duplicates(Ls), Ds).
Ls = Ds, Ds = [] ;
Ls = [_136],
Ds = [] ;
Ls = [_136, _136],
Ds = [_136] ;
Ls = [_156, _162],
Ds = [],
dif(_162, _156) ;
Ls = Ds, Ds = [_42, _42, _42] ;
Ls = [_174, _174, _186],
Ds = [_174],
dif(_186, _174) .
Multiple occurrences
Here is a version that handles arbitrary many occurrences of the same element in such a way that exactly a single occurrence is retained if (and only if) the element occurs at least twice:
list_duplicates(Ls, Ds) :-
phrase(list_duplicates(Ls, []), Ds).
list_duplicates([], _) --> [].
list_duplicates([L|Ls], Ds0) -->
list_duplicates_(Ls, L, Ds0, Ds),
list_duplicates(Ls, Ds).
list_duplicates_([], _, Ds, Ds) --> [].
list_duplicates_([L0|Ls], L, Ds0, Ds) -->
if_(L0=L, new_duplicate(L0, Ds0, Ds1), {Ds0 = Ds1}),
list_duplicates_(Ls, L, Ds1, Ds).
new_duplicate(E, Ds0, Ds) -->
new_duplicate_(Ds0, E, Ds0, Ds).
new_duplicate_([], E, Ds0, [E|Ds0]) --> [E].
new_duplicate_([L|Ls], E, Ds0, Ds) -->
if_(L=E,
{ Ds0 = Ds },
new_duplicate_(Ls, E, Ds0, Ds)).
The query shown by #fatalize in the comments now yields:
?- list_duplicates([a,a,a], Ls).
Ls = [a].
The other examples yield the same results. For instance:
?- list_duplicates([a,b,c], Ds).
Ds = [].
?- list_duplicates([a,b,a], Ds).
Ds = [a].
?- list_duplicates([a,b,X], Ds).
X = a,
Ds = [a] ;
X = b,
Ds = [b] ;
Ds = [],
dif(X, b),
dif(X, a).
?- list_duplicates([X,Y], Ds).
X = Y,
Ds = [Y] ;
Ds = [],
dif(Y, X).
I leave the case ?- list_duplicates(Ls, Ls). as an exercise.
Generality: Multiple directions
Ideally, we want to be able to use a relation in all directions.
For example, our program should be able to answer questions like:
What does a list look like if its duplicates are [a,b]?
With the version shown above, we get:
?- list_duplicates(Ls, [a,b]).
nontermination
Luckily, a very simple change allows as to answer such questions!
One such change is to simply write:
list_duplicates(Ls, Ds) :-
length(Ls, _),
phrase(list_duplicates(Ls, []), Ds).
This is obviously declaratively admissible, because Ls must be a list. Operationally, this helps us to enumerate lists in a fair way.
We now get:
?- list_duplicates(Ls, [a,b]).
Ls = [a, a, b, b] ;
Ls = [a, b, a, b] ;
Ls = [a, b, b, a] ;
Ls = [a, a, a, b, b] ;
Ls = [a, a, b, a, b] ;
Ls = [a, a, b, b, a] ;
Ls = [a, a, b, b, b] ;
Ls = [a, a, b, b, _4632],
dif(_4632, b),
dif(_4632, a) ;
etc.
Here is a simpler case, using only a single element:
?- list_duplicates(Ls, [a]).
Ls = [a, a] ;
Ls = [a, a, a] ;
Ls = [a, a, _3818],
dif(_3818, a) ;
Ls = [a, _3870, a],
dif(_3870, a) ;
Ls = [_4058, a, a],
dif(a, _4058),
dif(a, _4058) ;
Ls = [a, a, a, a] ;
etc.
Maybe even more interesting:
What does a list without duplicates look like?
Our program answers:
?- list_duplicates(Ls, []).
Ls = [] ;
Ls = [_3240] ;
Ls = [_3758, _3764],
dif(_3764, _3758) ;
Ls = [_4164, _4170, _4176],
dif(_4176, _4164),
dif(_4176, _4170),
dif(_4170, _4164) .
Thus, the special case of a list where all elements are distinct naturally exists as a special case of the more general relation we have implemented.
We can use this relation to generate answers (as shown above), and also to test whether a list consists of distinct elements:
?- list_duplicates([a,b,c], []).
true.
?- list_duplicates([b,b], []).
false.
Unfortunately, the following even more general query still yields:
?- list_duplicates([b,b|_], []).
nontermination
On the plus side, if the length of the list is fixed, we get in such cases:
?- length(Ls, L), maplist(=(b), Ls),
( true ; list_duplicates(Ls, []) ).
Ls = [],
L = 0 ;
Ls = [],
L = 0 ;
Ls = [b],
L = 1 ;
Ls = [b],
L = 1 ;
Ls = [b, b],
L = 2 ;
Ls = [b, b, b],
L = 3 ;
Ls = [b, b, b, b],
L = 4 .
This is some indication that the program indeed terminates in such cases. Note that the answers are of course now too general.
Efficiency
It is well known in high-performance computing circles that as long as your program is fast enough, its correctness is barely worth considering.
So, the key question is of course: How can we make this faster?
I leave this is a very easy exercise. One way to make this faster in specific cases is to first check whether the given list is sufficiently instantiated. In that case, you can apply an ad hoc solution that fails terribly in more general cases, but has the extreme benefit that it is fast!
So as far as I can tell, you were on the right track with the accumulator, but this implementation definitely works as you want (assuming you want the duplicates in the order they first appear in the list).
list_duplicates(Input,Output) is just used to wrap and initialise the accumulator.
list_duplicates(Accumulator,[],Accumulator) unifies the accumulator with the output when we have finished processing the input list.
list_duplicates(Accumulator,[H|T],Output) says "if the head (H) of the input list is in the rest of the list (T), and is not in the Accumulator already, put it at the end of the Accumulator (using append), then recurse on the tail of the list".
list_duplicates(Accumulator,[_|T],Output) (which we only get to if either the head is not a duplicate, or is already in the Accumulator) just recurses on the tail of the list.
list_duplicates(Input,Output) :-
once(list_duplicates([],Input,Output)).
list_duplicates(Accumulator,[],Accumulator).
list_duplicates(Accumulator,[H|T],Output) :-
member(H,T),
\+member(H,Accumulator),
append(Accumulator,[H],NewAccumulator),
list_duplicates(NewAccumulator,T,Output).
list_duplicates(Accumulator,[_|T],Output) :-
list_duplicates(Accumulator,T,Output).
You could also recurse in list_duplicates(Accumulator,[H|T],Output) with list_duplicates([H|Accumulator],T,Output) and reverse in the wrapper, looking like this:
list_duplicates(Input,Output) :-
once(list_duplicates([],Input,ReverseOutput)),
reverse(ReverseOutput,Output).
list_duplicates(Accumulator,[],Accumulator).
list_duplicates(Accumulator,[H|T],Output) :-
member(H,T),
\+member(H,Accumulator),
list_duplicates([H|Accumulator],T,Output).
list_duplicates(Accumulator,[_|T],Output) :-
list_duplicates(Accumulator,T,Output).
The once call in the wrapper prevents the false output (or in this case, partial duplicate lists due to a lack of guards on the second rule).

Intersection of two lists without duplicate elements in Prolog

I need to write a program that finds the intersection of two lists. I can't use cuts and there shouldn't be any duplicate elements in the result list.
This is my code:
intersection([],_,[]).
intersection([X|Xs],Y,[X|Zs]) :-
member(X,Y),
intersection(Xs,Y,Zs).
intersection([_|Xs],Y,Zs) :-
intersection(Xs,Y,Zs).
When I run the following query, I get these answers:
?- intersection([a,b,c,a],[a,v,c],L).
L = [a, c, a] ;
L = [a, c] ; % <---------- this is only answer I want to get
L = [a, a] ;
L = [a] ;
L = [c, a] ;
L = [c] ;
L = [a] ;
L = [].
What can I do? I want to get L = [a,c] and nothing else... Can you help?
In my answer to the related question "Intersection and union of 2 lists" I presented the logically pure predicate list_list_intersectionSet/3. It should fit your requirements to a T!
Here's is a brushed-up version of list_list_intersectionSet/3, which is based on:
monotone conditional if_/3,
meta-predicate tfilter/3,
and the reified test predicates dif/3 and memberd_t/3.
Here we go:
list_list_intersectionSet([] ,_ ,[]).
list_list_intersectionSet([A|As0],Bs,Cs0) :-
if_(memberd_t(A,Bs), Cs0 = [A|Cs], Cs0 = Cs),
tfilter(dif(A),As0,As),
list_list_intersectionSet(As,Bs,Cs).
Let's see it in action!
?- list_list_intersectionSet([a,b,c,a],[a,v,c],L).
L = [a,c].
If by "conjunction" you mean "intersection", you should take a look at the implementation in the SWI-Prolog library(lists) of the predicate intersection/3. It contains cuts, but you can leave them out if you don't mind all the choicepoints.
With it:
?- intersection([a,b,c,a],[a,v,c],I).
I = [a, c, a].
Of course, this doesn't work even in the library predicate, because you need sets with your current definition. (It is enough if only the first argument is a set.)
You can make sets with the sort/2 predicate: if the first argument is a list with repetitions, the second argument will be a sorted list without repetitions, for example:
?- sort([a,b,c,a], S1), intersection(S1, [a,v,c], I).
S1 = [a, b, c],
I = [a, c].
or maybe:
?- sort([a,b,c,a], S1), intersection(S1, [a,v,c,c,a,c], I).
S1 = [a, b, c],
I = [a, c].
?- sort([a,b,c,a,b,c,a,b,c], S1), intersection(S1, [a,v,c,c,a,c], I).
S1 = [a, b, c],
I = [a, c].
If you sort both arguments, you can use a ord_intersection/3 from library(ordsets), implemented in terms of oset_int/3.
?- sort([a,b,c,a], S1), sort([a,v,c,c,a,c], S2), ord_intersection(S1, S2, I).
S1 = [a, b, c],
S2 = [a, c, v],
I = [a, c].
Importantly, oset_int/3 does not use any cuts in its implementation. It however assumes that the first and second arguments are lists of elements sorted by the "standard order of terms" and without duplicates, as done by sort/2.
If for some reason you don't want to use sort/2, you could maybe use an accumulator and check against it before taking an element to the intersection:
my_intersection(Xs, Ys, Zs) :-
my_intersection_1(Xs, Ys, [], Zs).
my_intersection_1([], _, Zs, Zs).
my_intersection_1([X|Xs], Ys, Zs0, Zs) :-
member(X, Ys), \+ member(X, Zs0),
my_intersection_1(Xs, Ys, [X|Zs0], Zs).
my_intersection_1([_|Xs], Ys, Zs0, Zs) :-
my_intersection_1(Xs, Ys, Zs0, Zs).
Of course, the order of the elements in the result will be now reversed. If this is not what you mean by "conjunction", you could for example rewrite the first two clauses of my_intersection_1/4 as:
my_intersection_1([], _, _, []).
my_intersection_1([X|Xs], Ys, Zs0, [X|Zs]) :-
member(X, Ys), \+ member(X, Zs0),
my_intersection_1(Xs, Ys, [X|Zs0], Zs).
The previously shown list_list_intersectionSet/3 restricts the item order in the intersection:
?- list_list_intersectionSet([a,b],[a,b], [a,b]).
true.
?- list_list_intersectionSet([a,b],[a,b], [b,a]).
false.
In this answer we lift that restriction... preserving logical-purity and determinism (for ground cases)!
First, we define none_intersect/2 using Prolog lambdas and
meta-predicate maplist/2.
none_intersect(As,Bs) states that all members in As are different from all members in Bs.
:- use_module(library(lambda)).
none_intersect(As,Bs) :-
maplist(\A^maplist(dif(A),Bs),As).
Next, we define intersection_of_and/3---based on none_intersect/2 (defined above), meta-predicate tpartition/4 and reified term equality (=)/3:
intersection_of_and([],As,Bs) :-
none_intersect(As,Bs).
intersection_of_and([X|Xs],As0,Bs0) :-
tpartition(=(X),As0,[_|_],As), % [_|_] = [X|_]
tpartition(=(X),Bs0,[_|_],Bs), % [_|_] = [X|_]
intersection_of_and(Xs,As,Bs).
intersection_of_and(Xs,As,Bs) states that
all items which occur in both As and Bs also occur in Xs (first clause),
all items in Xs occur in both As and Bs at least once (second clause),
and the list Xs does not contain any duplicates.
intersection_of_and/3 uses a specific argument in order to enable first argument indexing.
Last, we define list_list_intersection/3 which has the argument order that the OP used:
list_list_intersection(As,Bs,Xs) :-
intersection_of_and(Xs,As,Bs).
Let's run some queries! First, the query that the bounty offerer suggested:
?- list_list_intersection([a,b],[a,b], [b,a]).
true.
Next, a similar query with 3 distinct items in 3 lists having 3 different orders:
?- list_list_intersection([a,b,c],[b,a,c], [c,a,b]).
true.
What if some x only occurs in the first/second list?
?- list_list_intersection([a,b,c,x],[b,a,c], [c,a,b]).
true.
?- list_list_intersection([a,b,c],[b,a,c,x], [c,a,b]).
true.
What if some item occurs twice in the first/second list?
?- list_list_intersection([a,b,c],[b,a,c,b], [c,a,b]).
true.
?- list_list_intersection([a,b,c,c],[b,a,c], [c,a,b]).
true.
Last, what if the intersection contains duplicates?
Intersections are not to contain duplicates...
?- list_list_intersection([a,b,c],[b,a,c], [c,c,a,b]).
false. % as expected
Seems like something like this would be the easy way:
intersection( Xs , Ys , Zs ) :-
sort(Xs,X1) , % order and de-dupe the 1st list so as to produce a set
sort(Ys,Y1) , % order and de-dupe the 2nd list so as to produce a set
merge(Xs,Ys,Zs) % merge the two [ordered] sets to produce the result
. % easy!
merge( [] , [] , [] ) .
merge( [] , [_|_] , [] ) .
merge( [_|_] , [] , [] ) .
merge( [X|Xs] , [Y|Ys] , [X|Zs] ) :- X = Y , merge( Xs , Ys , Zs ) .
merge( [X|Xs] , [Y|Ys] , Zs ) :- X < Y , merge( Xs , [Y|Ys] , Zs ) .
merge( [X|Xs] , [Y|Ys] , Zs ) :- X > Y , merge( [X|Xs] , Ys , Zs ) .
Or even just this [not-terribly-performant] one-liner:
intersection( Xs , Ys , Zs ) :- setof(Z,(member(Z,Xs),member(Z,Ys)),Zs).
This can be solved by simple set theory:
intersection(A,B,AnB):-
subtract(A,B,AminusB),
subtract(A,AminusB,K),
sort(K,AnB).
For the query:
?- intersection([a,b,c,a],[a,v,c],L).
output is
L = [a, c].
No more answers.

How to predicate all pairs in a given list in Prolog?

When given a list I would like to compute all the possible combinations of pairs in the list.
e.g 2) input is a list (a,b,c) I would like to obtain pairs (a,b) (a,c) (b,c)
e.g 1) input is a list (a,b,c,d) I would like to obtain pairs (a,b) (a,c) (a,d) (b,c) (b,d) and (c,d)
Using select/3 twice (or select/3 once and member/2 once) will allow you to achieve what you want here. I'll let you work out the details and ask for help if it's still troublesome.
BTW, Prolog syntax for list isn't (a, b, c) but [a, b, c] (well, it's syntactic sugar but I'll leave it at that).
edit: as #WillNess pointed out, you're not looking for any pair (X, Y) but only for pairs where X is before Y in the list.
DCGs are a really good fit: as #false described, they can produce a graphically appealing solution:
... --> [] | [_], ... .
pair(L, X-Y) :-
phrase((..., [X], ..., [Y], ...), L).
Alternatively, if you use SWI-Prolog, a call to append/2 does the trick too, in a similar manner, but is less efficient than DCGs:
pair2(L, X-Y) :-
append([_, [X], _, [Y], _], L).
You can do it with a basic recursion, as #WillNess suggested in his comment. I'll leave this part for him to detail if needed!
OK, so to translate the Haskell definition
pairs (x:xs) = [ (x,y) | y <- xs ]
++ pairs xs
pairs [] = []
(which means, pairs in the list with head x and tail xs are all the pairs (x,y) where y is in xs, and also the pairs in xs; and there's no pairs in an empty list)
as a backtracking Prolog predicate, producing the pairs one by one on each redo, it's a straightforward one-to-one re-write of the above,
pair( [X|XS], X-Y) :- member( ... , XS) % fill in
; pair( XS, ... ). % the blanks
%% pair( [], _) :- false.
To get all the possible pairs, use findall:
pairs( L, PS) :- findall( P, pair( L, P), PS).
Consider using bagof if your lists can contain logical variables in them. Controlling bagof's backtracking could be an intricate issue though.
pairs can also be written as a (nearly) deterministic, non-backtracking, recursive definition, constructing its output list through an accumulator parameter as a functional programming language would do -- here in the top-down manner, which is what Prolog so excels in:
pairs( [X|T], PS) :- T = [_|_], pairs( X, T, T, PS, []).
pairs( [_], []).
pairs( [], []).
pairs( _, [], [], Z, Z).
pairs( _, [], [X|T], PS, Z) :- pairs( X, T, T, PS, Z).
pairs( X, [Y|T], R, [X-Y|PS], Z) :- pairs( X, T, R, PS, Z).
Here is a possible way of solving this.
The following predicate combine/3 is true
if the third argument corresponds to a list
contains pairs, where the first element of each pair
is equal to the first argument of combine/3.
The second element of each pair will correspond to an item
of the list in the second argument of the predicate combine/3.
Some examples how combine/3 should work:
?- combine(a,[b],X).
X = [pair(a,b)]
?- combine(a,[b,c,d],X).
X = [pair(a,b), pair(a,c), pair(a,d)]
Possible way of defining combine/3:
combine(A,[B],[pair(A,B)]) :- !.
combine(A,[B|T],C) :-
combine(A,T,C2), % Create pairs for remaining elements in T.
append([pair(A,B)],C2,C). % Append current pair and remaining pairs C2.
% The result of append is C.
Now combine/3 can be used to define pair/2:
pairs([],[]). % Empty list will correspond to empty list of pairs.
pairs([H|T],P) :- % In case there is at least one element.
nonvar([H|T]), % In this case it expected that [H|T] is instantiated.
pairs(H,T,P).
pairs(A,[B],[pair(A,B)]) % If remaining list contains exactly one element,
:- !. % then there will be only one pair(A,B).
pairs(A,[B|T],P) :- % In case there are at least two elements.
combine(A,[B|T],P2), % For each element in [B|T] compute pairs
% where first element of each pair will be A.
pairs(B,T,P3), % Compute all pairs without A recursively.
append(P2,P3,P). % Append results P2 and P3 together.
Sample usage:
?- pairs([a,b,c],X).
X = [pair(a, b), pair(a, c), pair(b, c)].
?- pairs([a,b,c,d],X).
X = [pair(a, b), pair(a, c), pair(a, d), pair(b, c), pair(b, d), pair(c, d)].
You can use append/ to iterate through the list:
?- append(_,[X|R],[a,b,c,d]).
X = a,
R = [b, c, d] ;
X = b,
R = [c, d] ;
X = c,
R = [d] ;
X = d,
R = [] ;
false.
Next, use member/2 to form a pair X-Y, for each Y in R:
?- append(_,[X|R],[a,b,c,d]), member(Y,R), Pair=(X-Y).
X = a,
R = [b, c, d],
Y = b,
Pair = a-b ;
X = a,
R = [b, c, d],
Y = c,
Pair = a-c ;
X = a,
R = [b, c, d],
Y = d,
Pair = a-d ;
X = b,
R = [c, d],
Y = c,
Pair = b-c ;
X = b,
R = [c, d],
Y = d,
Pair = b-d ;
X = c,
R = [d],
Y = d,
Pair = c-d ;
false.
Then, use findall/3 to collect all pairs in a list:
?- findall(X-Y, (append(_,[X|R],[a,b,c,d]), member(Y,R)), Pairs).
Pairs = [a-b, a-c, a-d, b-c, b-d, c-d].
Thus, your final solution can be expressed as:
pairs(List, Pairs) :-
findall(X-Y, (append(_,[X|R],List), member(Y,R)), Pairs).
An example of use is:
?- pairs([a,b,c,d], Pairs).
Pairs = [a-b, a-c, a-d, b-c, b-d, c-d].