Longest common prefix (LCP) of a list of strings - list

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).

Related

Why does my Prolog predicate invert/2 not work?

I'm new to Prolog and as an exercise I want to make an list invertion predicate. It uses the add_tail predicate that I made earlier—some parts might be redundant, but I don't care:
add_tail(A, [], A) :-
!.
add_tail([A|[]], H, [A,H]) :-
!.
add_tail([A|B], H, [A|C]) :-
add_tail(B,H,C).
It works same as builtin predicate append/3:
?- add_tail([a,b,c], d, A).
A = [a, b, c, d].
?- append([a,b,c], [d], A).
A = [a, b, c, d].
When I use append in my invert predicate, it works fine, but if I use add_tail, it fails:
invert([], []).
invert([A|B], C) :-
invert(B, D),
append(D, [A], C).
invert2([], []).
invert2([A|B], C) :-
invert2(B, D),
add_tail(D, A, C).
?- invert([a,b,c,d], A).
A = [d, c, b, a].
?- invert2([a,b,c,d], A).
false. % expected answer A = [d,c,b,a], like above
What exactly is my mistake? Thank you!
The implementation of add_tail/3 does not quite behave the way you expect it to.
Consider:
?- append([], [d], Xs).
Xs = [d].
?- add_tail([], d, Xs).
false.
That's bad... But it gets worse! There are even more issues with the code you presented:
By using (!)/0 you needlessly limit the versatility of your predicate.
Even though [A|[]] maybe correct, it obfuscates your code. Use [A] instead!
add_tail is a bad name for a predicate that works in more than one direction.
The variable names could be better, too! Why not use more descriptive names like As?
Look again at the variables you used in the last clause of add_tail/3!
add_tail([A|B], H, [A|C]) :-
add_tail(B, H, C).
Consider the improved variable names:
add_tail([A|As], E, [A|Xs]) :-
add_tail(As, E, Xs).
I suggest starting over like so:
list_item_appended([], X, [X]).
list_item_appended([E|Es], X, [E|Xs]) :-
list_item_appended(Es, X, Xs).
Let's put list_item_appended/3 to use in list_reverted/2!
list_reverted([], []).
list_reverted([E|Es], Xs) :-
list_reverted(Es, Fs),
list_item_appended(Fs, E, Xs).
Sample query:
?- list_reverted([a,b,c,d], Xs).
Xs = [d, c, b, a].
It is difficult to pinpoint your exact mistake, but the first two clauses of add_tail/3, the ones with the cuts, are wrong (unless I am misunderstanding what the predicate is supposed to do). Already the name is a bit misleading, and you should should care that you have redundant code.
list_back([], B, [B]).
list_back([X|Xs], B, [X|Ys]) :-
list_back(Xs, B, Ys).
This is a drop-in replacement for your add_tail/3 in your definition of invert/2. But as you are probably aware, this is not a very clever way of reversing a list. The textbook example of how to do it:
list_rev(L, R) :-
list_rev_1(L, [], R).
list_rev_1([], R, R).
list_rev_1([X|Xs], R0, R) :-
list_rev_1(Xs, [X|R0], R).
First try the most general query, to see which solutions exist in the most general case:
?- add_tail(X, Y, Z).
yielding the single answer:
X = Z,
Y = []
That's probably not the relation you intend to define here.
Hint: !/0 typically destroys all logical properties of your code, including the ability to use your predicates in all directions.
The first clause of add_tail/3 has a list as second argument, so it will never apply to your test case. Then we are left with 2 clauses (simplified)
add_tail([A],H,[A,H]):-!.
add_tail([A|B],H,[A|C]) :- add_tail(B,H,C).
You can see that we miss a matching clause for the empty list as first argument. Of course, append/3 instead has such match.
based on previous answer of "#mat" the problem is residue in the first two lines
your predicate add_tail is not like append because
with append i get this
| ?- append(X,Y,Z).
Z = Y,
X = [] ? ;
X = [_A],
Z = [_A|Y] ? ;
X = [_A,_B],
Z = [_A,_B|Y] ? ;
X = [_A,_B,_C],
Z = [_A,_B,_C|Y] ? ;
X = [_A,_B,_C,_D],
Z = [_A,_B,_C,_D|Y] ? ;
X = [_A,_B,_C,_D,_E],
Z = [_A,_B,_C,_D,_E|Y] ? ;y
and unfortunately with ur add_tail i get this result
| ?- add_tail(X,Y,Z).
Z = X,
Y = [] ? ;
X = [_A],
Z = [_A|Y] ? ;
X = [_A|_B],
Y = [],
Z = [_A|_B] ? ;
X = [_A,_B],
Z = [_A,_B|Y] ? ;
X = [_A,_B|_C],
Y = [],
Z = [_A,_B|_C] ?
X = [_A,_B,_C],
Z = [_A,_B,_C|Y] ? y
yes
after a simple modification in your add_tail code i obtained your expected result
code
% add_tail(A,[],A):-! . comment
add_tail([],H,H) :-!.
add_tail([A|B],H,[A|C]) :- add_tail(B,H,C).
test add_tail
| ?- add_tail(X,Y,Z).
Z = Y,
X = [] ? ;
X = [_A],
Z = [_A|Y] ? ;
X = [_A,_B],
Z = [_A,_B|Y] ? ;
X = [_A,_B,_C],
Z = [_A,_B,_C|Y] ? ;
X = [_A,_B,_C,_D],
Z = [_A,_B,_C,_D|Y] ? ;
X = [_A,_B,_C,_D,_E],
Z = [_A,_B,_C,_D,_E|Y] ? y
yes
finaly
i test ur invert predicate without modification
| ?- invert([_A,_B,_C],L).
L = [_C,_B,_A] ? ;
no
I hope this post help you to explain how the predicate done inside
enjoy

Length ordered subsets?

I'm trying to make a code that generates all subsets of a set in order.
That is, calling subset([1,2,3], X) should generate
X = [];
X = [1];
X = [2];
X = [3];
X = [1,2];
X = [1,3];
X = [2,3];
X = [1,2,3].
The internal order isn't all that important, only that the smallest subsets are listed first (i.e I don't care if [2,3] comes before [1,2], only that 1, [2] and [3] are before [2,3]).
--
I've tried two approaches thus far. First I tried making the predicate myself...
subset([], []).
subset(List, []).
subset(List, [N]) :-
member(N, List).
subset(List, [N|Rest]) :-
!,
nth0(I, List, N),
findall(E, (nth0(J, List, E), J > I), NewList),
subset2(NewList, Rest).
...but it doesn't even come close to working as intended. Secondly I tried making the powerset (using this subset predicate) and ordering with list_to_ord_set/2, but I couldn't get it to work either.
Help?
Always also consider using DCG notation when describing lists.
For example:
list_sublist(Ls0, Ls) :-
same_length(Ls0, Ls1),
append(Ls, _, Ls1),
phrase(sublist(Ls0), Ls).
sublist([]) --> [].
sublist([L|Ls]) --> ( [] ; [L] ), sublist(Ls).
Sample query:
?- list_sublist([a,b,c], Ls).
Ls = [] ;
Ls = [c] ;
Ls = [b] ;
Ls = [a] ;
Ls = [b, c] ;
Ls = [a, c] ;
Ls = [a, b] ;
Ls = [a, b, c] ;
false.
Another example:
?- list_sublist(Ls, [b,c]).
Ls = [b, c] ;
Ls = [_G511, b, c] ;
Ls = [b, _G514, c] ;
Ls = [b, c, _G517] ;
etc.
Most general case:
?- list_sublist(Xs, Ys).
Xs = Ys, Ys = [] ;
Xs = [_G513],
Ys = [] ;
Xs = Ys, Ys = [_G513]
Xs = [_G513, _G516],
Ys = [] ;
etc.
I've found a not so elegant solution... it requires a cut and some builtins
subset(Xs, Ys) :-
length(Xs, L),
between(0, L, N),
length(Ys, N),
assign(Xs, Ys).
assign(_, []) :- !.
assign([X|Xs], [X|Ys]) :-
assign(Xs, Ys).
assign([_|Xs], Ys) :-
assign(Xs, Ys).
as noted by #Fatalize, we can avoid the cut, just forcing the empty list on first argument of 1^ clause:
assign([], []).
assign([X|Xs], [X|Ys]) :-
assign(Xs, Ys).
assign([_|Xs], Ys) :-
assign(Xs, Ys).
I avoided to swap 2^ and 3^ clauses, so the 'natural' order is still nicely preserved

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. :)

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].

Split a list in half

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.