Split a list in half - list

I need to define divide so that List [1,2,3,4,5] divides into:
a = [1,2,3}
b = [4,5]
I'm getting an error that says "Arguments are not sufficiently instantiated", and I don't know enough about the language to figure out what my problem is, or if my design is even right. Any guidance would be appreciated.
So here's what I have so far:
append([],L2,L2).
append([H|T],L2,[H|L3]) :- append(T,L2,L3).
lengthIs([],N).
lengthIs([H|T],N) :- lengthIs(T,M), N is M+1.
divide([],[],[]).
divide([H|T],L2,L3) :-
( lengthIs(L2, M) < lengthIs(L1,N)/2
-> divide(T, append(L2, H, X), L3)
; divide(T, L2, append(L3,H,Y))
).

Let's give the predicate a more relational name: list_half_half/3
list_half_half(Xs, Ys, Zs) :-
length(Xs, N),
H is N - N // 2,
length(Ys, H),
append(Ys, Zs, Xs).
length/2 and append/3 are predefined in practically all recent Prologs.
This is GNU Prolog:
| ?- append(L,_,[a,b,c,d]), list_half_half(L,H1,H2).
H1 = []
H2 = []
L = [] ? ;
H1 = [a]
H2 = []
L = [a] ? ;
H1 = [a]
H2 = [b]
L = [a,b] ? ;
H1 = [a,b]
H2 = [c]
L = [a,b,c] ? ;
H1 = [a,b]
H2 = [c,d]
L = [a,b,c,d]

This is the most efficient solution conforming to your specification for most Prolog implementations:
divide(L, A, B) :-
divide1(L, L, A, B).
divide1([], L, [], L).
divide1([_|T], [H|L], [H|A], B) :-
divide2(T, L, A, B).
divide2([], L, [], L).
divide2([_|T], L, A, B) :-
divide1(T, L, A, B).
If you don't mind which elements go into the sublists as far as they are of similar length (as in the solution from Konstantin Weitz post), then you can use :
divide([], [], []).
divide([H|T], [H|A], B) :- divide(T, B, A).

append is a pre-defined predicate, so that might be the issue: http://en.wikibooks.org/wiki/Prolog/Lists#The_append_predicate
You also never defined 'N' in lengthIs - you need to set the empty list as 0, not N/
There's likely also a size function
The underscore tells Prolog we don't care about that bit in that predicate definition.
Something like this should work
divide(L1,L2,L3):- append(L2,L3,L1),
samesize(L2,L3).
divide(L1,L2,L3):- append(L2,L3,L1),
onebigger(L2,L3).
samesize(A,B):- size(A,N),
size(B,N).
onebigger(A,[_|T]):- size(A,N),
size(T,N).
size([],0).
size([H|T],N):- size(T,M+1).

Surely the effect of this code (lengthIs(L2, M) < lengthIs(L1,N)/2 -> ...) isn't what you expect: it doesn't compare numbers, but terms. You should write it this way:
lengthIs(L2, M), lengthIs(L1, N), M < N/2 -> ...
Another typo like mistake: the first clause of lengthIs/2 should read
lengthIs([],0).

No need to check sizes. Just do it like this:
div([],[],[]).
div([A],[A],[]).
div([A,B|T],[A|X],[B|Y]) :- div(T,X,Y).

Here's a sort of "rabbit and hare" approach.
divide(Xs,Ys,Zs) :-
divide(Xs,Xs,Ys,Zs).
divide(Ls,[],[],Ls).
divide([H|Ts],[_],[H],Ts).
divide([H|Ts],[_,_|Zs],[H|Us],Rs)
:- divide(Ts,Zs,Us,Rs).
The divide/4 predicate works but stripping both a single element and a double element from the initial list. By the time the second argument gets to the empty list or a list of one element then we are effectively halfway through the list passed as the first argument.
It's effectively O(n/2) complexity.
Here's a sample output:
?- divide([a,b,c,d,e,f,g,h],X,Y).
X = [a, b, c, d],
Y = [e, f, g, h] .
?- divide([a,b,c,d,e,f,g],X,Y).
X = [a, b, c, d],
Y = [e, f, g] .

Another answer,
uses Backtracking a lot, isn't very performant, though.
append and length are assumed to be predefined:
divide(A,B,C):-
append(B,C,A),
length(B,B_Length),
length(C,C_Length),
(B_Length = C_Length;
B_Length =:= C_Length +1).
Oh, sorry, just have seen that this is sort of a rephrasing of the answer from Philip Whitehouse.

This is how I did it. Almost no built-ins:
split_list_in_half( Xs , H , T ) :-
list_length( X , L ) ,
LL = L - (L // 2) ,
take_first( Xs , LL , H , T ) ,
.
list_length( L , N ) :-
list_length( L , 0 , N )
.
list_length( [] , N , N ).
list_length( [X|Xs] , T , N ) :-
T1 is T+1 ,
list_length( Xs , T1 , N )
.
take_first( Xs , N , Pfx , Sfx ) :-
take_first( Xs , N , [] , P1 , Sfx ) ,
reverse( P1 , Pfx )
.
take_first( [] , _ , H , H , [] ).
take_first( [X|Xs] , 0 , H , H , [X|Xs] ).
take_first( [X|Xs] , N , H1 , H , T ) :-
N > 0 ,
N1 = N-1 ,
take_first( Xs , N1 , [X|H1] , H , T )
.

Improved head-and-tail iteration, guarding against infinity:
split_list_half([A,B|T], Half1, Half2) :-
split_list_half_([A,B|T], [A,B|T], Half1, Half2, Half2).
split_list_half_([], H2, [], _, H2).
% H2D prevents infinity with: split_list_half(L, H1, [c, d]).
split_list_half_([_|T], [H|Sgl], H1, H2D, H2) :-
split_list_half_dbl_(T, H, Sgl, H1, H2D, H2).
split_list_half_dbl_([], H, H2, [H], _, H2).
split_list_half_dbl_([_|T], H, Sgl, [H|H1], [_|H2D], H2) :-
split_list_half_(T, Sgl, H1, H2D, H2).
Results in swi-prolog:
?- split_list_half([a,b,c,d], H1, H2).
H1 = [a, b],
H2 = [c, d].
?- split_list_half([a,b,c,d,e], H1, H2).
H1 = [a, b, c],
H2 = [d, e].
?- split_list_half(LF, H1, [d, e]).
LF = [_A, _B, d, e],
H1 = [_A, _B] ;
LF = [_A, _B, _C, d, e],
H1 = [_A, _B, _C] ;
false.

Related

Returning false if item is not in list (PROLOG)

Below is the code to remove a key (A) from a list if it is there. If it isn't there, it currently returns the entire list. I would like it instead to return 'false.' Sample outputs will be below as well.
mySelect(_, [], []).
mySelect(X, [Y|K], [Y|M]):- mySelect(X, K, M), (X \= Y).
mySelect(X, [X|K], R) :- mySelect(X, K, R).
Currently this will output:
?- my_delete(c,[a,b,c,d],R).
R = [a, b, d] .
?- my_delete(e,[a,b,c,d],R).
R = [a, b, c, d] .
I would like it to output:
?- my_delete(c,[a,b,c,d],R).
R = [a, b, d] .
?- my_delete(e,[a,b,c,d],R).
false .
Any pointers would be greatly appreciated!
You can add another rule which first ensures that X is a member of L, before applying mySelect.
delete(X, L, R) :- member(X, L), mySelect(X, L, R).
Either partition the list into matches and non-matches:
filter( X , Ys, Zs ) :- filter(X,Ys,[_|_],Zs).
filter( _ , [] , [] , [] ) .
filter( X , [X|Ys] , [X|Xs] , Zs ) :- !, filter(X,Ys,Xs,Zs) .
filter( X , [Y|Ys] , Xs , [Y|Zs] ) :- filter(X,Ys,Xs,Zs) .
or count the number of items and test the count for being greater than zero:
filter( X , Ys, Zs ) :- filter(X,Ys,0,N,Zs), N > 0 .
filter( _ , [] , N , N , [] ) .
filter( X , [X|Ys] , T , N , Zs ) :- T1 is T+1, !, filter(X,Ys,T1,N, Zs) .
filter( X , [Y|Ys] , T , N , [Y|Zs] ) :- !, filter(X,Ys,T,N,Zs) .

Prolog: P-12: Ninety-Nine Prolog Problems (Modified)

I am trying to decode a specific list with two different elements, either e.g. [4, a] or just b
I expect decode([[4,a],b,[2,c],[2,a],d,[4,e]], X). to result into X=[a,a,a,a,b,c,c,a,a,d,e,e,e,e].
with
decode([], []).
decode([[N, X]|Xs], R) :-
create_list(N, X, L1),
append(L1, R),
decode(Xs, R).
decode([X|Xs], [X|R]) :-
\+ is_list(X),
decode(Xs, R).
create_list(0, _, []).
create_list(N, X, [X|R]) :-
N > 0,
N1 is N - 1,
create_list(N1, X, R).
Generates only false and I have tested the create_list predicate and it works.
I have no clue what I'm missing but could just be a minor mistake. But I have tried for a while to find the problem without success so why not ask here :) The question is a modified version from the Ninety-Nine Prolog Problems (Problem 12).
Your problem lies in the use of append/2 which concatenates a list of lists, but you have a list of atoms.
You may use append/3 to build a list with an unbound tail and pass that tail to the recursive step of your procedure, i.e.:
decode([], []).
decode([[N, X]|Xs], R) :-
create_list(N, X, L1),
append(L1, Tail, R),
decode(Xs, Tail).
decode([X|Xs], [X|R]) :-
\+ is_list(X),
decode(Xs, R).
create_list(0, _, []).
create_list(N, X, [X|R]) :-
N > 0,
N1 is N - 1,
create_list(N1, X, R).
Sample run:
?- decode([[4,a],b,[2,c],[2,a],d,[4,e]], X).
X = [a, a, a, a, b, c, c, a, a, d, e, e, e, e] ;
false.
You may also get rid of append altogether by adding a third argument to create_list which holds that tail:
decode([], []).
decode([[N, X]|Xs], R) :-
create_list(N, X, R, Tail),
decode(Xs, Tail).
decode([X|Xs], [X|R]) :-
\+ is_list(X),
decode(Xs, R).
create_list(0, _, Tail, Tail).
create_list(N, X, [X|R], Tail) :-
N > 0,
N1 is N - 1,
create_list(N1, X, R, Tail).
Alternatively you may get rid of create_list by using length/2 and maplist/2:
decode([], []).
decode([[N, X]|Xs], R) :-
length(L, N),
maplist(=(X), L),
append(L, Tail, R),
decode(Xs, Tail).
decode([X|Xs], [X|R]) :-
\+ is_list(X),
decode(Xs, R).
This is a problem of run-length encoding and run-length decoding.
Run-length encoding is easy:
encode( [] , [] ) . % the run-length encoding of the empty list is the empty list
encode( [X|Xs] , [R|Ys] ) :- % For non-empty lists,
run(Xs,X:1,R,Rs), % - seed the run with the first element and compute the run length
encode(Rs, Ys) % - then recurse down
. % Easy!
run( [] , Y:N , Y:N , [] ) .
run( [X|Xs] , Y:N , Y:N , [X|Xs] ) :- X \== Y .
run( [X|Xs] , Y:T , N , Rs ) :- X == Y , T1 is T+1 , run(Xs,Y:T1,N,Rs) .
And decoding a run-length encoded list is the opposite
decode( [] , [] ) . % the run-length decoding of the empty list is the empty list
decode( [X:N|Xs] , Ys ) :- % for non-empty lists,
expand(X,N,Ys,Zs) , % - expand the run
decode(Xs,Zs) % - recurse down
.
expand( _ , 0 , Zs , Zs ) .
expand( X , N , [X|Ys] , Zs ) :-
N > 0,
N1 is N-1,
expand(X,N1,Ys,Zs)
.
And then put it together in a transcoder that will work bi-directionally:
run_length_transcode( PlainText, RleText ) :- nonvar( PlainText ) , encode( PlainText , RleText ).
run_length_transcode( PlainText, RleText ) :- nonvar( RleText ) , decode( RleText , PlainText ).

Longest common prefix (LCP) of a list of strings

lcs([ H|L1],[ H|L2],[H|Lcs]) :-
!,
lcs(L1,L2,Lcs).
lcs([H1|L1],[H2|L2],Lcs):-
lcs( L1 ,[H2|L2],Lcs1),
lcs([H1|L1], L2 ,Lcs2),
longest(Lcs1,Lcs2,Lcs),
!.
lcs(_,_,[]).
longest(L1,L2,Longest) :-
length(L1,Length1),
length(L2,Length2),
( Length1 > Length2
-> Longest = L1
; Longest = L2
).
This is my code so far. How could I optimize it so that it prints the prefix, e.g.:
["interview", "interrupt", "integrate", "intermediate"]
should return "inte"
A bit rusty with Prolog, haven't done it in a while :)
First, let's start with something related, but much simpler.
:- set_prolog_flag(double_quotes, chars). % "abc" = [a,b,c]
prefix_of(Prefix, List) :-
append(Prefix, _, List).
commonprefix(Prefix, Lists) :-
maplist(prefix_of(Prefix), Lists).
?- commonprefix(Prefix, ["interview", "integrate", "intermediate"]).
Prefix = []
; Prefix = "i"
; Prefix = "in"
; Prefix = "int"
; Prefix = "inte"
; false.
(See this answer, how printing character lists with double quotes is done.)
This is the part that is fairly easy in Prolog. The only drawback is that it doesn't give us the maximum, but rather all possible solutions including the maximum. Note that all strings do not need to be known, like:
?- commonprefix(Prefix, ["interview", "integrate", Xs]).
Prefix = []
; Prefix = "i", Xs = [i|_A]
; Prefix = "in", Xs = [i, n|_A]
; Prefix = "int", Xs = [i, n, t|_A]
; Prefix = "inte", Xs = [i, n, t, e|_A]
; false.
So we get as response a partial description of the last unknown word. Now imagine, later on we realize that Xs = "induce". No problem for Prolog:
?- commonprefix(Prefix, ["interview", "integrate", Xs]), Xs = "induce".
Prefix = [], Xs = "induce"
; Prefix = "i", Xs = "induce"
; Prefix = "in", Xs = "induce"
; false.
In fact, it does not make a difference whether we state this in hindsight or just before the actual query:
?- Xs = "induce", commonprefix(Prefix, ["interview", "integrate", Xs]).
Xs = "induce", Prefix = []
; Xs = "induce", Prefix = "i"
; Xs = "induce", Prefix = "in"
; false.
Can we now based on this formulate the maximum? Note that this effectively necessitates some form of extra quantor for which we do not have any direct provisions in Prolog. For this reason we have to limit us to certain cases we know will be safe. The easiest way out would be to insist that the list of words does not contain any variables. I will use iwhen/2 for this purpose.
maxprefix(Prefix, Lists) :-
iwhen(ground(Lists), maxprefix_g(Prefix, Lists)).
maxprefix_g(Prefix, Lists_g) :-
setof(N-IPrefix, ( commonprefix(IPrefix, Lists_g), length(IPrefix, N ) ), Ns),
append(_,[N-Prefix], Ns). % the longest one
The downside of this approach is that we get instantiation errors should the list of words not be known.
Note that we made quite some assumptions (which I hope really hold). In particular we assumed that there is exactly one maximum. In this case this holds, but in general it could be that there are several independent values for Prefix. Also, we assumed that IPrefix will always be ground. We could check that too, just to be sure. Alternatively:
maxprefix_g(Prefix, Lists_g) :-
setof(N, IPrefix^ ( commonprefix(IPrefix, Lists_g), length(IPrefix, N ) ), Ns),
append(_,[N], Ns),
length(Prefix, N),
commonprefix(Prefix, Lists_g).
Here, the prefix does not have to be one single prefix (which it is in our situation).
The best, however, would be a purer version that does not need to resort to instantiation errors at all.
Here's the purified variant of the code proposed (and subsequently retracted) by #CapelliC:
:- set_prolog_flag(double_quotes, chars).
:- use_module(library(reif)).
lists_lcp([], []).
lists_lcp([Es|Ess], Ls) :-
if_((maplist_t(list_first_rest_t, [Es|Ess], [X|Xs], Ess0),
maplist_t(=(X), Xs))
, (Ls = [X|Ls0], lists_lcp(Ess0, Ls0))
, Ls = []).
list_first_rest_t([], _, _, false).
list_first_rest_t([X|Xs], X, Xs, true).
Above meta-predicate maplist_t/3 is a variant of maplist/2
which works with term equality/inequality reification—maplist_t/5 is just the same with higher arity:
maplist_t(P_2, Xs, T) :-
i_maplist_t(Xs, P_2, T).
i_maplist_t([], _P_2, true).
i_maplist_t([X|Xs], P_2, T) :-
if_(call(P_2, X), i_maplist_t(Xs, P_2, T), T = false).
maplist_t(P_4, Xs, Ys, Zs, T) :-
i_maplist_t(Xs, Ys, Zs, P_4, T).
i_maplist_t([], [], [], _P_4, true).
i_maplist_t([X|Xs], [Y|Ys], [Z|Zs], P_4, T) :-
if_(call(P_4, X, Y, Z), i_maplist_t(Xs, Ys, Zs, P_4, T), T = false).
First here's a ground query:
?- lists_lcp(["a","ab"], []).
false. % fails (as expected)
Here are the queries presented in #Fatalize's fine answer.
?- lists_lcp(["interview",X,"intermediate"], "inte").
X = [i,n,t,e]
; X = [i,n,t,e,_A|_B], dif(_A,r)
; false.
?- lists_lcp(["interview","integrate",X], Z).
X = Z, Z = []
; X = Z, Z = [i]
; X = Z, Z = [i,n]
; X = Z, Z = [i,n,t]
; X = Z, Z = [i,n,t,e]
; X = [i,n,t,e,_A|_B], Z = [i,n,t,e]
; X = [i,n,t,_A|_B] , Z = [i,n,t] , dif(_A,e)
; X = [i,n,_A|_B] , Z = [i,n] , dif(_A,t)
; X = [i,_A|_B] , Z = [i] , dif(_A,n)
; X = [_A|_B] , Z = [] , dif(_A,i).
?- lists_lcp([X,Y], "abc").
X = [a,b,c] , Y = [a,b,c|_A]
; X = [a,b,c,_A|_B], Y = [a,b,c]
; X = [a,b,c,_A|_B], Y = [a,b,c,_C|_D], dif(_A,_C)
; false.
?- lists_lcp(L, "abc").
L = [[a,b,c]]
; L = [[a,b,c],[a,b,c|_A]]
; L = [[a,b,c,_A|_B],[a,b,c]]
; L = [[a,b,c,_A|_B],[a,b,c,_C|_D]], dif(_A,_C)
; L = [[a,b,c],[a,b,c|_A],[a,b,c|_B]]
; L = [[a,b,c,_A|_B],[a,b,c],[a,b,c|_C]]
; L = [[a,b,c,_A|_B],[a,b,c,_C|_D],[a,b,c]]
; L = [[a,b,c,_A|_B],[a,b,c,_C|_D],[a,b,c,_E|_F]], dif(_A,_E)
…
Last, here's the query showing improved determinism:
?- lists_lcp(["interview","integrate","intermediate"], Z).
Z = [i,n,t,e]. % succeeds deterministically
Here is how I would implement this:
:- set_prolog_flag(double_quotes, chars).
longest_common_prefix([], []).
longest_common_prefix([H], H).
longest_common_prefix([H1,H2|T], P) :-
maplist(append(P), L, [H1,H2|T]),
( one_empty_head(L)
; maplist(head, L, Hs),
not_all_equal(Hs)
).
one_empty_head([[]|_]).
one_empty_head([[_|_]|T]) :-
one_empty_head(T).
head([H|_], H).
not_all_equal([E|Es]) :-
some_dif(Es, E).
some_dif([X|Xs], E) :-
if_(diffirst(X,E), true, some_dif(Xs,E)).
diffirst(X, Y, T) :-
( X == Y -> T = false
; X \= Y -> T = true
; T = true, dif(X, Y)
; T = false, X = Y
).
The implementation of not_all_equal/1 is from this answer by #repeat (you can find my implementation in the edit history).
We use append and maplist to split the strings in the list into a prefix and a suffix, and where the prefix is the same for all strings. For this prefix to be the longest, we need to state that the first character of at least two of the suffixes are different.
This is why we use head/2, one_empty_head/1 and not_all_equal/1. head/2 is used to retrieve the first char of a string; one_empty_head/1 is used to state that if one of the suffixes is empty, then automatically this is the longest prefix. not_all_equal/1 is used to then check or state that at least two characters are different.
Examples
?- longest_common_prefix(["interview", "integrate", "intermediate"], Z).
Z = [i, n, t, e] ;
false.
?- longest_common_prefix(["interview", X, "intermediate"], "inte").
X = [i, n, t, e] ;
X = [i, n, t, e, _156|_158],
dif(_156, r) ;
false.
?- longest_common_prefix(["interview", "integrate", X], Z).
X = Z, Z = [] ;
X = [_246|_248],
Z = [],
dif(_246, i) ;
X = Z, Z = [i] ;
X = [i, _260|_262],
Z = [i],
dif(_260, n) ;
X = Z, Z = [i, n] ;
X = [i, n, _272|_274],
Z = [i, n],
dif(_272, t) ;
X = Z, Z = [i, n, t] ;
X = [i, n, t, _284|_286],
Z = [i, n, t],
dif(_284, e) ;
X = Z, Z = [i, n, t, e] ;
X = [i, n, t, e, _216|_224],
Z = [i, n, t, e] ;
false.
?- longest_common_prefix([X,Y], "abc").
X = [a, b, c],
Y = [a, b, c|_60] ;
X = [a, b, c, _84|_86],
Y = [a, b, c] ;
X = [a, b, c, _218|_220],
Y = [a, b, c, _242|_244],
dif(_218, _242) ;
false.
?- longest_common_prefix(L, "abc").
L = [[a, b, c]] ;
L = [[a, b, c], [a, b, c|_88]] ;
L = [[a, b, c, _112|_114], [a, b, c]] ;
L = [[a, b, c, _248|_250], [a, b, c, _278|_280]],
dif(_248, _278) ;
L = [[a, b, c], [a, b, c|_76], [a, b, c|_100]] ;
L = [[a, b, c, _130|_132], [a, b, c], [a, b, c|_100]];
…
This previous answer presented an implementation based on if_/3.
:- use_module(library(reif)).
Here comes a somewhat different take on it:
lists_lcp([], []).
lists_lcp([Es|Ess], Xs) :-
foldl(list_list_lcp, Ess, Es, Xs). % foldl/4
list_list_lcp([], _, []).
list_list_lcp([X|Xs], Ys0, Zs0) :-
if_(list_first_rest_t(Ys0, Y, Ys) % if_/3
, ( Zs0 = [X|Zs], list_list_lcp(Xs, Ys, Zs) )
, Zs0 = []
).
list_first_rest_t([], _, _, false).
list_first_rest_t([X|Xs], Y, Xs, T) :-
=(X, Y, T). % =/3
Almost all queries in my previous answer give the same answers, so I do not show them here.
lists_lcp([X,Y], "abc"), however, does not terminate universally anymore with the new code.
A simple version:
:- set_prolog_flag(double_quotes, chars).
pref([],_,[]).
pref(_,[],[]).
pref([H|T1],[H|T2],[H|Tr]):-
pref(T1,T2,Tr).
pref([H|_],[H|_],[]).
pref([H1|_],[H2|_],[]):-
dif(H1,H2).
lcf([],[]).
lcf([W],R):-
pref(W,W,R).
lcf([W1,W2|L],R):-
pref(W1,W2,R),
lcf([W2|L],R).
Examples:
pref("interview","integrate",R).
R = [i, n, t, e] ;
R = [i, n, t] ;
R = [i, n] ;
R = [i] ;
R = [] ;
False.
lcf(["interview", "interrupt", "integrate", "intermediate"],R).
R = [i, n, t, e]
lcf(["interview", "interrupt", X, "intermediate"],R).
R = X, X = [i, n, t, e, r]
I recently had to implement this for two lists, and this is the code I came up with. It assumes the two input lists are sufficiently instantiated.
longest_common_prefix([X|Xs], [X|Ys], [X|Common]) :- !,
longest_common_prefix(Xs, Ys, Common).
longest_common_prefix(_, _, []).
This is easily extended to multiple lists:
lcs([], []).
lcs([L1|Ls], Prefix) :-
foldl(longest_common_prefix, Ls, L1, Prefix).
If you don't like using foldl:
lcs([], []).
lcs([L1|Ls], Prefix) :-
lcs(Ls, L1, Prefix).
lcs([], Prefix, Prefix).
lcs([L1|Ls], Prefix0, Prefix) :-
longest_common_prefix(L1, Prefix0, Prefix1),
lcs(Ls, Prefix1, Prefix).

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 can I remove the last n elements from a list in Prolog?

I would like to delete the last n elements of a list in Prolog and put it in another list say L2. If I knew the exact number of elements to delete say 3, here is the code. But I am stuck with the variable n case. Btw I would like to return an empty string if the length of the list is shorter than n. Thank you.
without_last_three([], []).
without_last_three([_], []).
without_last_three([_,_], []).
without_last_three([_,_,_], []).
without_last_three([Head|Tail], [Head|NTail]):-
without_last_three(Tail, NTail).
without_last_n(Old, N, New) :-
length(Tail, N),
append(New, Tail, Old).
Test run:
?- without_last_n([a, b, c, d, e, f], 4, New).
New = [a, b]
?- without_last_n([a, b, c, d, e, f], 777, New).
false.
?- without_last_n([a, b, c, d, e, f], 0, New).
New = [a, b, c, d, e, f]
Update. To succeed with an [] when N is bigger than the length of the list, second clause can be added:
without_last_n(Old, N, []) :-
length(Old, L),
N > L.
Here is a general case:
without_last_n(L, N, []) :-
nonvar(L), nonvar(N),
length(L, M),
N > M.
without_last_n(L, N, R) :-
without_last_n_(L, N, R).
without_last_n_(L, N, []) :-
length(L, N).
without_last_n_([H|T], N, [H|T1]) :-
without_last_n_(T, N, T1).
This satisfies the given requirements, and works with a variety of variable instantiation scenarios. What complicates the solution a bit is the requirement that without_last_n(L, N, []). must succeed if N is greater than the length of L. If this was not a requirement, then the much simpler without_last_n_/3 would suffice as a solution to the problem.
Testing...
| ?- without_last_n([1,2,3,4], 3, R).
R = [1] ? ;
no
| ?- without_last_n([1,2,3,4], N, R).
N = 4
R = [] ? ;
N = 3
R = [1] ? ;
N = 2
R = [1,2] ? ;
N = 1
R = [1,2,3] ? ;
N = 0
R = [1,2,3,4]
(1 ms) yes
| ?- without_last_n([1,2,3,4], N, [1,2]).
N = 2 ? ;
no
| ?- without_last_n(L, 3, [1,2]).
L = [1,2,_,_,_] ? ;
no
| ?- without_last_n(L, 2, R).
L = [_,_]
R = [] ? ;
L = [A,_,_]
R = [A] ? ;
L = [A,B,_,_]
R = [A,B] ? ;
L = [A,B,C,_,_]
R = [A,B,C] ?
...
| ?- without_last_n(L, N, [1,2]).
L = [1,2]
N = 0 ? ;
L = [1,2,_]
N = 1 ? ;
L = [1,2,_,_]
N = 2 ? ;
...
| ?- without_last_n(L, N, R).
L = []
N = 0
R = [] ? ;
L = [_]
N = 1
R = [] ? ;
L = [_,_]
N = 2
R = [] ? ;
L = [_,_,_]
N = 3
R = [] ? ;
...
| ?-
A possible flaw here is that without_last_n([1,2,3,4], N, R). perhaps could generate solutions ad infinitum of N = 5, R = [], N = 6, R = [], etc. But it doesn't. Left as an exercise for the reader. :)