Related
Given the frequent pure definition of same_length/2 as
same_length([],[]).
same_length([_|As], [_|Bs]) :-
same_length(As, Bs).
?- same_length(L, [_|L]).
loops.
Is there a pure definition that does not loop for such cases? Something in analogy to the pure (but less efficient) version of append/3 called append2u/3.
I know how to catch such cases manually with var/1 and the like, but ideally a version that is just as pure as the original definition would be desirable. Or at least it should be simple.
What I have tried is the definition above.
One clarification seems to be in order:
Note that there are certain queries that inherently must not terminate. Think of:
?- same_length(Ls, Ks).
Ls = [], Ks = []
; Ls = [_A], Ks = [_B]
; Ls = [_A,_B], Ks = [_C,_D]
; Ls = [_A,_B,_C], Ks = [_D,_E,_F]
; Ls = [_A,_B,_C,_D], Ks = [_E,_F,_G,_H]
; ... .
There is no other way to enumerate all solutions using the language of syntactic answer substitutions.
But still an implementation may terminate for the queries given.
This answer aims at minimising runtime costs.
It is built on '$skip_max_list'/4 and runs on Scryer Prolog.
First up, some auxiliary code:
:- use_module(library(lists)).
'$skip_list'(N,Xs0,Xs) :-
'$skip_max_list'(N,_,Xs0,Xs).
is_list([]).
is_list([_|Xs]) :-
is_list(Xs).
sam_length_([],[]).
sam_length_([_|Xs],[_|Ys]) :-
sam_length_(Xs,Ys).
Now the main dish:
sam_length(Ls1,Ls2) :-
'$skip_list'(L1,Ls1,Rs1),
( Rs1 == []
-> length(Ls2,L1)
; var(Rs1),
'$skip_max_list'(L2,L1,Ls2,Rs2),
( L2 < L1
-> var(Rs2),
Rs1 \== Rs2,
'$skip_max_list'(_,L2,Ls1,Ps1),
sam_length_(Ps1,Rs2)
; '$skip_list'(N2,Rs2,Ts2),
( Ts2 == []
-> M1 is N2-L1,
length(Rs1,M1)
; var(Ts2),
( N2 > 0
-> Ts2 \== Rs1,
sam_length_(Rs2,Rs1) % switch argument order
; Rs1 == Rs2
-> is_list(Rs1) % simpler enumeration
; sam_length_(Rs1,Rs2)
)
)
)
).
Sample queries:
?- sam_length(L,[_|L]).
false.
?- sam_length([_],L).
L = [_A].
?- sam_length(L,M).
L = [], M = []
; L = [_A], M = [_B]
; ... .
A solution using '$skip_max_list'/4:
% Clause for `?- L = [a|L], same_length(L, _)`.
same_length(As, Bs) :-
(Cs = As ; Cs = Bs),
'$skip_max_list'(_, _, Cs, Cs0),
subsumes_term([_|_], Cs0), !,
false.
% Clause for `?- same_length(L, [_|L])`.
same_length(As, Bs) :-
As \== Bs,
'$skip_max_list'(S, _, As, As0),
'$skip_max_list'(T, _, Bs, Bs0),
As0 == Bs0,
S \== T, !,
false.
same_length(As, Bs) :-
same_length_(As, Bs).
same_length_([], []).
same_length_([_|As], [_|Bs]) :-
same_length_(As, Bs).
Queries:
?- L = [a|L], same_length(L, _).
false.
?- same_length(L, [_|L]).
false.
?- same_length([_], L).
L = [_A].
?- same_length(L, M).
L = [], M = []
; L = [_A], M = [_B]
; ... .
UPDATED SOLUTION
Here is my solution:
same_length(A, A).
same_length([_|A], [_|B]) :- same_length(A, B).
?- same_length(L, [_|L]).
L = [_1696|L]
I am not sure if it has all the properties you're looking for. For example if you call
? - same_length(L, [1,2,3]).
then it lists many answers, e.g. L = [_X, 2, 3], rather than just [_X, _Y, _Z]. But it's pure and produces a correct answer for the query quoted.
I am trying to get a set of elements from a list in prolog, such that a query:
get_elems([1, 2, 4, 10], [a, b, c, d, e], X).
yields:
X = [a, b, d]
I would like to implement it without using the built in predicate nth.
I have tried using the following, but it does not work:
minus_one([], []).
minus_one([X|Xs], [Y|Ys]) :- minus_one(Xs, Ys), Y is X-1.
get_elems([], _, []).
get_elems(_, [], []).
get_elems([1|Ns], [A|As], Z) :- get_elems(Ns, As, B), [A|B] = Z.
get_elems(Ns, [_|As], Z) :- minus_one(Ns, Bs), get_elems(Bs, As, Z).
Edit: The list of indices is guaranteed to be ascending, also I want to avoid implementing my own version of nth.
Give this a go:
get_elems(Xs,Ys,Zs) :- get_elems(Xs,1,Ys,Zs).
get_elems(Xs,_,Ys,[]) :- Xs = []; Ys = [].
get_elems([N|Xs],N,[H|Ys],[H|Zs]) :- !, N1 is N + 1, get_elems(Xs,N1,Ys,Zs).
get_elems(Xs,N,[_|Ys],Zs) :- N1 is N + 1, get_elems(Xs,N1,Ys,Zs).
This just keeps counting up and when the head of the second term is equal to the current index it peels off the head and makes it the head of the current output term. If it doesn't match it just discards the head and keeps going.
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).
I tried to create something what would work like this:
?- unpacking([[1], [1,2], [3]], Lst1, NewLst).
NewLst=[1,3]
I wrote it like this:
unpacking([], Lst1, Lst1).
unpacking([[H]|T], Lst1, NewLst):-
append([H], Lst2),
unpacking(T, Lst2, NewLst).
unpacking([_|T], Lst1, NewLst):-
unpacking(T, Lst1, NewLst).
and I know that I am doing something wrong. I am starting in Prolog so, need to learn from my mistakes :)
You probably meant:
unpacking([], []).
unpacking([[E]|T], [E|L]) :-
unpacking(T, L).
unpacking([[]|T], L) :-
unpacking(T, L).
unpacking([[_,_|_]|T], L) :-
unpacking(T, L).
There are more concise ways to write this - and more efficient, too.
What about this :
%?-unpacking([[a,b,c],[a],[b],[c,d]],Items).
unpacking(Lists,Items):-
my_tpartition(length_t(1),Lists,Items,Falses).
my_tpartition(P_2,List,Ts,Fs) :- my_tpartition_ts_fs_(List,Ts,Fs,P_2).
my_tpartition_ts_fs_([],[],[],_).
my_tpartition_ts_fs_([X|Xs0],Ts,Fs,P_2) :-
if_(call(P_2,X), (X=[NX],Ts = [NX|Ts0], Fs = Fs0),
(Ts = Ts0, Fs = [X|Fs0])),
my_tpartition_ts_fs_(Xs0,Ts0,Fs0,P_2).
length_t(X,Y,T):-
length(Y,L1),
=(X,L1,T).
This is based on Most general higher-order constraint describing a sequence of integers ordered with respect to a relation
* Update*
You could change to
length_t(X,Y,T):-
L1 #=< X,
fd_length(Y,L1),
=(X,L1,T),!.
length_t(_X,_Y,false).
fd_length(L, N) :-
N #>= 0,
fd_length(L, N, 0).
fd_length([], N, N0) :-
N #= N0.
fd_length([_|L], N, N0) :-
N1 is N0+1,
N #>= N1,
fd_length(L, N, N1).
giving:
?-unpacking([[1],[2,3],[4],[_,_|_]],U).
U= [1,4].
but:
?-unpacking([X],Xs).
X = Xs, Xs = [].
Based on #coder's solution, I made my own attempt using if_ and DCGs:
one_element_([], true).
one_element_([_|_],false).
one_element([], false).
one_element([_|Xs], T) :-
one_element_(Xs, T).
f([]) -->
[].
f([X|Xs]) -->
{ if_(one_element(X), Y=X, Y=[]) },
Y,
f(Xs).
unpack(Xs,Ys) :-
phrase(f(Xs),Ys).
I only tried for about 30s, but the queries:
?- Xs = [[] | Xs], unpack(Xs,Ys).
?- Xs = [[_] | Xs], unpack(Xs,Ys).
?- Xs = [[_, _ | _] | Xs], unpack(Xs,Ys).
didn't stop with a stack overflow. In my opinion, the critical one should be the last query, but apparently, SWI Prolog manages to optimize:
?- L = [_,_|_], one_element(L,T).
L = [_3162, _3168|_3170],
T = false.
Edit: I improved the solution and gave it a shot with argument indexing. According to the SWI Manual, indexing happens if there is exactly a case distinction between the empty list [] and the non-empty list [_|_]. I rewrote one_element such that it does exactly that and repeated the trick with the auxiliary predicate one_element_. Now that one_element is pure again, we don't lose solutions anymore:
?- unpack([A,B],[]).
A = [_5574, _5580|_5582],
B = [_5628, _5634|_5636] ;
A = [_5574, _5580|_5582],
B = [] ;
A = [],
B = [_5616, _5622|_5624] ;
A = B, B = [].
but
?- unpack([[a,b,c],[a],[b],[c,d]],Items).
Items = [a, b].
is still deterministic. I have not tried this solution in other Prologs, which might be missing the indexing, but it seems for SWI, this is a solution.
Update: Apparently GNU Prolog does not do this kind of indexing and overflows on cyclic lists:
| ?- Xs = [[] | Xs], unpack(Xs,Ys).
Fatal Error: global stack overflow (size: 32770 Kb, reached: 32768 Kb, environment variable used: GLOBALSZ)
After some thought, here is my implementation using if_/3:
unpacking(L,L1):-if_( =(L,[]), L1=[], unpack(L,L1)).
unpack([H|T],L):-if_(one_element(H), (H = [X],L=[X|T1],unpacking(T,T1)), unpacking(T,L)).
one_element(X, T) :-
( var(X) ->(T=true,X=[_]; T=false,X=[])
; X = [_] -> T = true
; X \= [_] -> T = false).
Some testcases:
?- unpacking([Xss],[]).
Xss = [].
?- unpacking([[1],[2,3],[4],[_,_|_]],U).
U = [1, 4].
?- unpacking([[1],[2,3],[4]],U).
U = [1, 4].
?- unpacking([[E]],[1]), E = 2.
false.
?- unpacking(non_list, []).
false.
?- unpacking([Xs],Xs).
Xs = [_G6221] ;
Xs = [].
UPDATE
To fix the case that #false referred in the comment we could define:
one_element([],false).
one_element([_],true).
one_element([_,_|_],false).
But this leaves some choice points...
One way to do it is with a findall I dont think its what the bounty is for though ;)
unpacking(Lists,L1):-
findall(I,(member(M,Lists),length(M,1),M=[I]),L1).
or
unpacking2(Lists,L1):-
findall(I,member([I],Lists),L1).
Hello is there any way to separate a list in Prolog into two other lists, the first includes everything before an element and the second everything after the element. For example
A=[1,2,3,5,7,9,0] and element=5
the two lists should be
A1=[1,2,3] and A2=[7,9,0]
I don't care about finding the element just what to do next
it's easy as
?- Elem = 5, A = [1,2,3,5,7,9,0], append(A1, [Elem|A2], A).
edit to explain a bit...
append/3 it's a relation among 3 lists.
It's general enough to solve any concatenation on proper lists - when not there are circular arguments.
The comparison it's a plain unification, that take place on second argument. That must be a list beginning with Elem. Prolog list constructor syntax is [Head|Tail]. To make unification succeed, Elem must match the Head.
Here's an alternative method, illustrating how to handle it with list recursion:
split([E|T], E, [], T).
split([X|T], E, [X|LL], LR) :-
X \== E,
split(T, E, LL, LR).
Or better, if your Prolog supports dif/2:
split([E|T], E, [], T).
split([X|T], E, [X|LL], LR) :-
dif(X, E),
split(T, E, LL, LR).
Examples:
| ?- split([1,2,3,4,5], 3, L, R).
L = [1,2]
R = [4,5] ? ;
no
| ?- split([1,2,3,4,5], 5, L, R).
L = [1,2,3,4]
R = [] ? ;
(1 ms) no
| ?- split([1,2,3,4,5], 1, L, R).
L = []
R = [2,3,4,5] ? ;
no
| ?-
It is a sort of specialized twist on append/3 as CapelliC showed.