I want to make one list of multiple sublists without using the flatten predicate in Prolog.
This is my code:
acclistsFromList([],A,A).
acclistsFromList([H|T],Listwithinlist,A):-
not(is_list(H)),
acclistsFromList(T,Listwithinlist,A).
acclistsFromList([H|T],Listwithinlist,A):-
is_list(H),
append([H],Listwithinlist,Acc2),
acclistsFromList(T,Acc2,A).
I get this as output
?- listsFromList([1,2,[a,b,c],3,4,[d,e]],X).
X = [[d, e], [a, b, c]] ;
But I want this:
?- listsFromList([1,2,[a,b,c],3,4,[d,e]],X).
X = [a, b, c, d, e] .
?- listsFromList([1,[],2,3,4,[a,b]],X).
X = [a, b] .
?- listsFromList([[[[a]]],b,c,d,e,[f]],X).
X = [f, a] .
?- listsFromList([[[[a]],b,[c]],d,e,[f]],X).
X = [f, a, b, c] .
What is the best way to reach this result, without using flatten?
The second clause of the acclistsFromList/3 does not do anything with H if it has verified that H is not a list, but you need to prepend the result with H.
acclistsFromList([H|T], Listwithinlist, [H|A]) :-
\+ is_list(H),
acclistsFromList(T, Listwithinlist, A).
but this is not sufficient. Since you prepend to the accumulator, the result is reversed. You do not need an accumulator here anyway:
acclistsFromList([], []).
acclistsFromList([H|T], [H|A]) :-
\+ is_list(H),
acclistsFromList(T, A).
acclistsFromList([H|T], Result):-
is_list(H),
append(H, Res1, Result),
acclistsFromList(T, Res1).
or without the "scalar" elements:
acclistsFromList([], []).
acclistsFromList([H|T], A) :-
\+ is_list(H),
acclistsFromList(T, A).
acclistsFromList([H|T], Result):-
is_list(H),
append(H, Res1, Result),
acclistsFromList(T, Res1).
This furthermore does not recurse on lists. A list of lists of lists will thus not be flattened. I leave it as an exercise to implement this.
This is a one-liner,
foo(X,L) :-
findall(Z, (member(A,X),is_list(A),member(Z,A)), L).
(as seen here).
To deal with multi-layered nested lists, we need to use a recursive predicate,
nembr(Z,A) :- % member in nested lists
is_list(A), member(B,A), nembr(Z,B)
;
\+ is_list(A), A=Z.
then use it instead of that final member call in findall's goal:
bar(X,L) :-
findall(Z, (member(A,X),is_list(A),nembr(Z,A)), L).
testing:
10 ?- foo([1,2,[a,b,c],3,4,[d,e]],X).
X = [a, b, c, d, e].
11 ?- bar([1,2,[a,b,c],3,4,[d,e]],X).
X = [a, b, c, d, e].
12 ?- bar([1,2,[a,b,[[[c]]]],3,4,[d,e]],X).
X = [a, b, c, d, e].
In case you want to roll your own, here's breadth-first enumeration of arbitrarily nested lists:
bfs( XS, L) :- bfs( s(z), [XS|Q], Q, L, []).
bfs( z, _, _, Z, Z).
bfs( s(N), [[] |P], Q, L, Z) :- bfs( N, P, Q, L, Z).
bfs( s(N), [[A|B]|P], Q, L, Z) :-
is_list(A) % if is_list(A),
-> Q = [A|R], bfs( s(s(N)), [B|P], R, L, Z) % then enqueue A,
; L = [A|R], bfs( s(N), [B|P], Q, R, Z). % otherwise produce A
The first argument is the distance between read and write point on the queue. When they meet the queue has become exhausted and we stop. Both the input queue and the output list are maintained as difference list pairs of head and tail variables.
Trying it out:
12 ?- bfs( [[[6]],1,2,[4,[[[[[7]]]]],5],3], A).
A = [1, 2, 3, 4, 5, 6, 7] .
You will need to augment it to skip the non-lists in the top level.
A solution that uses an "open list" to append the elements encountered while walking the list-of-lists, which is essentially a tree, in prefix fashion.
The indicated examples indicate that non-list elements at depth 0 shall be discarded, and the other elements sorted by depth. However, no precise spec is given.
Indeed, one would expect the result of flattening
[[[[a]],b,[c]],d,e,[f]]
to be
[b,f,c,a]
via the "sorted-by-depth" pair list of Depth-Value pairs:
[3-a,1-b,2-c,1-f]
But the question poster requests this result instead:
[f, a, b, c]
I don't really know whether this is an error or not.
:- debug(flatwalker).
flatwalker(ListIn,ListOut) :-
Tip=Fin, % 2 unbound variables
% % designating the same memory
% % cell. Hold the Tip, grow at Fin.
flatwalker_2(0,ListIn,Fin,TerFin), % Elements are appended at Fin.
% % The final Fin is found in TerFin
% % on success.
TerFin=[], % Unify TerFin with [], closing
% % the list at Tip.
keysort(Tip,Sorted), % Sort the closed list at Tip
% % by pair key, i.e. by depth.
% % keysort/2 is stable and keeps
% % duplicates.
debug(flatwalker,"Got : ~q",[Tip]),
maplist([_-V,V]>>true,Sorted,ListOut). % Remove depth values.
% ---
% flatwalker_2(+Depth,+TreeIn,+Fin,+TerFin)
% Depth: Input integer, indicates current tree depth.
% TreeIn: The list to flatten at this depth (it's a node of the tree,
% which may or may not contain subtrees, i.e. lists)
% Fin: Always an unbound variable denoting the end of an open list to
% which we will append.
% ("points to an empty memory cell at the fin of the open list")
% Works as an accumulator as a new Fin, advanced by 1 cell at each
% append operation is handed to the next flatwalker_2/4
% activation.
% TerFin: When flatwalker_2/ is done, the final Fin is unified with
% TerFin so that it can be passed to flatwalker/2.
% ---
% We make the guards explicit and cut heavily.
% Optimizing the guards (if so desired) is left as an exercise.
flatwalker_2(_,[],Fin,Fin) :- !. % Done as TreeIn is empty.
% Unify Fin with TerFin.
flatwalker_2(0,[X|Xs],Fin,TerFin) :- % Case of X is nonlist at depth 0:
% % discard!
\+is_list(X),!,
flatwalker_2(0,Xs,Fin,TerFin). % Continue with the rest of the
% list at this depth.
flatwalker_2(D,[X|Xs],Fin,TerFin) :- % Case of X is nonlist at
% % depth > 0: keep!
D>0,\+is_list(X),!,
Fin=[D-X|Fin2], % Grow the result list at its
% % Fin by D-X.
flatwalker_2(D,Xs,Fin2,TerFin). % Continue with the rest of the
% list at this depth.
flatwalker_2(D,[X|Xs],Fin,TerFin) :- % Case of X is a list at any
% % depth.
is_list(X),!,
DD is D+1,
flatwalker_2(DD,X,Fin,Fin2), % Collect one level down
flatwalker_2(D,Xs,Fin2,TerFin). % On return, continue with the
% rest of the list at this depth.
Some plunit tests:
:- begin_tests(flatwalker).
test("empty",true(Out == [])) :-
flatwalker([],Out).
test("simple",true(Out == [])) :-
flatwalker([1,2,3],Out).
test("with empties",true(Out == [])) :-
flatwalker([[],1,[],2,[],3,[]],Out).
test("test 1",true(Out == [a, b, c, d, e])) :-
flatwalker([1,2,[a,b,c],3,4,[d,e]],Out).
test("test 2",true(Out == [a, b])) :-
flatwalker([1,[],2,3,4,[a,b]],Out).
test("test 3",true(Out == [f, a])) :-
flatwalker([[[[a]]],b,c,d,e,[f]],Out).
test("test 4",true(Out == [f, a, b, c])) :-
flatwalker([[[[a]],b,[c]],d,e,[f]],Out).
:- end_tests(flatwalker).
And so:
?- run_tests.
% PL-Unit: flatwalker
% Got : []
.
% Got : []
.
% Got : []
.
% Got : [1-a,1-b,1-c,1-d,1-e]
.
% Got : [1-a,1-b]
.
% Got : [3-a,1-f]
.
% Got : [3-a,1-b,2-c,1-f]
ERROR: flatwalker.pl:66:
test test 4: wrong answer (compared using ==)
ERROR: Expected: [f,a,b,c]
ERROR: Got: [b,f,c,a]
done
% 1 test failed
% 6 tests passed
false.
Related
I would like to get the middle element of a list in Prolog.
The predicates middle([1,2,3],M) and middle([1,2,3,4],M) should both return 2 as a result.
And I am allowed to use the predicate deleteLast.
I know that there are similar posts that solve that question but I have not found one that just uses deleteLast.
Even the syntax is not correct - however this is my solution so far:
middle([], _).
middle([X|XTail|Y], E) :-
1 is mod(list_length([X|XTail|Y], 2)),
middle([XTail], E).
middle([X|XTail|Y], E) :-
0 is mod(list_length([X|XTail|Y], 2)),
middle([X|XTail], E).
middle([X], X).
Question: Is that partly correct or am I completely on the wrong path ?
Sorry, the attempted solution you have is completely on the wrong path.
It doesn't use deleteLast/2 as you stated you require
You are using list_length/2 as if it were an arithmetic function, which it is not. It's a predicate.
You have a term with invalid syntax and unknown semantics, [X|XTail|Y]
In Prolog, you just need to think about it in terms of the rules. Here's an approach using deleteLast/2:
middle([X], X). % `X` is the middle of the single element list `[X]`
middle([X,_], X). % `X` is the middle of the two-element list `[X,_]`
% X is the middle of the list `[H|T]` if X is the middle of the list TWithoutLast
% where TWithoutLast is T with its last element removed
%
middle([H|T], X) :-
deleteLast(T, TWithoutLast),
middle(TWithoutLast, X).
I assume deleteLast/2 is well-behaved and just fails if T is empty.
You can also do this with same_length/2 and append/3, but, alas, doesn't use deleteLast/2:
middle(L, M) :-
same_length(L1, L2),
append(L1, [M|L2], L).
middle(L, M) :-
same_length(L1, L2),
append(L1, [M,_|L2], L).
So much unnecessary work, and unnecessary code. length/2 is very efficient, and a true relation. Its second argument is guaranteed to be a non-negative integer. So:
middle(List, Middle) :-
List = [_|_], % at least one element
length(List, Len),
divmod(Len, 2, Q, R), % if not available do in two separate steps
N is Q + R,
nth1(N, List, Middle).
And you are about ready:
?- middle(L, M), numbervars(L).
L = [A],
M = A ;
L = [A, B],
M = A ;
L = [A, B, C],
M = B ;
L = [A, B, C, D],
M = B ;
L = [A, B, C, D, E],
M = C ;
L = [A, B, C, D, E, F],
M = C .
I understand that this doesn't solve your problem (the answer by #lurker does) but it answers your question. :-(
Here is my attempt:
middle(L,M):- append(L1,L2,L),length(L1,N),length(L2,N), reverse(L1,[M|_]).
middle(L,M):- append(L1,L2,L),length(L1,N),length(L2,N1), N is N1+1 ,
reverse(L1,[M|_]).
Example:
?- middle([1,2,3],M).
M = 2 ;
false.
?- middle([1,2,3,4],M).
M = 2 ;
false.
In your implementation the problem is that by writing for example:
list_length([X|XTail|Y], 2)
The above does not give you as X the first element and as Y the last so I think it has some major problems...
As well pointed out by lurker you could write the above solution in one clause without using reverse/2:
middle(L, M) :- append(L1, [M|T], L), length(L1, N), length([M|T], N1),
(N1 is N + 1 ; N1 is N + 2).
Also to make the solution more relational (also see mat's comment below) you could use CLPFD library and replace is/2 with #= like:
middle(L, M) :- append(L1, [M|T], L), length(L1, N), length([M|T], N1),
(N1 #= N + 1 ; N1 #= N + 2).
Another interesting solution is to consider this predicate for splitting a list in half:
half(List, Left, Right) :-
half(List, List, Left, Right).
half(L, [], [], L).
half(L, [_], [], L).
half([H|T], [_,_|T2], [H|Left], Right) :-
half(T, T2, Left, Right).
This predicate divides an even list into two equal halves, or an odd list into two pieces where the right half has one more element than the left. It does so by reducing the original list, via the second argument, by two elements, each recursive call, while at the same time reducing the original list by one element each recursive call via the first argument. When it recurses down to the second argument being zero or one elements in length, then the first argument represents the half that's left, which is the right-hand list.
Example results for half/3 are:
| ?- half([a,b,c], L, R).
L = [a]
R = [b,c] ? a
(1 ms) no
| ?- half([a,b,c,d], L, R).
L = [a,b]
R = [c,d] ? a
no
| ?-
We can't quite use this to easily find the middle element because, in the even case, we want the last element of the left hand list. If we could bias the right-hand list by an extra element, we could then pick off the head of the right-hand half as the "middle" element. We can accomplish this using the deleteLast/2 here:
middle([X], X).
middle(List, Middle) :-
deleteLast(List, ListWithoutLast),
half(ListWithoutLast, _, [Middle|_]).
The head of the right half list of the original list, with the last element deleted, is the "middle" element. We can also simply half/3 and combine it with middle/2 since we don't really need everything half/3 does (e.g., we don't need the left-hand list, or the tail of the right hand list):
middle([X], X).
middle(List, Middle) :-
deleteLast(List, ListWithoutLast),
middle(ListWithoutLast, ListWithoutLast, Middle).
middle([M|_], [], M).
middle([M|_], [_], M).
middle([_|T], [_,_|T2], Right) :-
middle(T, T2, Right).
Another approach would be to modify half/3 to bias the splitting of the original list in half toward the right-hand half, which eliminates the need for using deleteLast/2.
modified_half(List, Left, Right) :-
modified_half(List, List, Left, Right).
modified_half(L, [_], [], L).
modified_half(L, [_,_], [], L).
modified_half([H|T], [_,_,X|T2], [H|Left], Right) :-
modified_half(T, [X|T2], Left, Right).
This will bias the right hand list to have an extra element at the "expense" of the left:
| ?- modified_half([a,b,c,d,e], L, R).
L = [a,b]
R = [c,d,e] ? a
no
| ?- modified_half([a,b,c,d,e,f], L, R).
L = [a,b]
R = [c,d,e,f] ? a
no
| ?-
Now we can see that the middle element, per the original definition, is just the head of the right hand list. We can create a new definition for middle/2 using the above. As we did before with half/3, we can ignore everything but the head in the right half, and we can eliminate the left half since we don't need it, and create a consolidated middle/2 predicate:
middle(List, Middle) :-
middle(List, List, Middle).
middle([M|_], [_,_], M).
middle([M|_], [_], M).
middle([_|T], [_,_,X|T2], Middle) :-
middle(T, [X|T2], Middle).
This reduces the original list down one element at a time (first argument) and two elements at a time (second argument) until the second argument is reduced to one or two elements. It then considers the head first argument to be the middle element:
This gives:
| ?- middle([a,b,c], M).
M = b ? ;
no
| ?- middle([a,b,c,d], M).
M = b ? ;
no
| ?- middle(L, M).
L = [M,_] ? ;
L = [M] ? ;
L = [_,M,_,_] ? ;
L = [_,M,_] ? ;
L = [_,_,M,_,_,_] ? ;
L = [_,_,M,_,_] ? ;
L = [_,_,_,M,_,_,_,_] ?
...
I am trying to make use of prolog predicates and find middle element of a given list. My idea was to cut first and last element of list using recursion.Unfortunately I dont know how to handle recursion call properly.
delete_last(L, L1) :-
append(L1, [_], L).
delete_first(L,L1) :-
append([_],L1,L).
check_len(L) :-
length(L,LEN), \+ 1 is LEN.
delete_both([],_):-
false.
delete_both([_,_],_) :-
false.
delete_both([X],X):-
true, write('MidElement').
delete_both(L,L2) :-
delete_first(LT,L2), delete_last(L,LT),check_len(LT)
->write('here should be recursive call only when length is more than one').
I would be grateful for any help.
It would save a lot of typing if you checked the length of the list, calculated the position of the middle element, and only then traversed the list to get the element at that position. With SWI-Prolog, this would be:
?- length(List, Len),
divmod(Len, 2, N, 1),
nth0(N, List, a).
List = [a], Len = 1, N = 0 ;
List = [_G2371, a, _G2377], Len = 3, N = 1 ;
List = [_G2371, _G2374, a, _G2380, _G2383], Len = 5, N = 2 . % and so on
This solution makes sure the list has an odd length. You can see the documentation of divmod/4 if you need to define it yourself. Or, if the list does not have to have and odd, length, just use N is Len div 2. If for some reason you are not allowed to use nth0/3, it is still an easier predicate to implement than what you are trying to do.
You can tighten up what you have quite a bit as follows:
delete_last(L, L1) :-
append(L1, [_], L).
delete_first([_|L], L).
% No need to check length of 1, since we only need to check
% if L = [X] in the caller, so we'll eliminate this predicate
%check_len(L) :-
% length(L, 1). % No need for an extra variable to check length is 1
% Clauses that yield false are not needed since clauses already fail if not true
% So you can just remove those
%
delete_both([X], X) :-
write('MidElement').
% Here you need to fix the logic in your main clause
% You are deleting the first element of the list, then the last element
% from that result and checking if the length is 1.
delete_both(L, X) :-
delete_first(L, L1), % Remove first and last elements from L
delete_last(L1, LT),
( LT = [X] % Check for length of 1
-> true
; delete_both(LT, X) % otherwise, X is result of delete_both(LT, X)
).
With results:
| ?- delete_both([a,b,c,d,e], X).
X = c
yes
| ?- delete_both([a,b,c,d,e,f], X).
no
A DCG solution also works well here:
% X is the middle if it is flanked by two sequences of the same length
%
middle(X) --> seq(N), [X], seq(N).
seq(0) --> [].
seq(N) --> [_], { N #= N1 + 1 }, seq(N1).
middle(List, X) :- phrase(middle(X), List).
With results:
| ?- middle([a,b,c,d,e], X).
X = c ? ;
(1 ms) no
| ?- middle(L, a).
L = [a] ? ;
L = [_,a,_] ? ;
L = [_,_,a,_,_] ?
...
Another possible solution is to use SWI Prolog's append/2 predicate, which appends a list of lists (assuming you're using SWI):
middle(L, X) :-
same_length(Left, Right),
append([Left, [X], Right], L).
same_length([], []).
same_length([_|T1], [_|T2]) :- same_length(T1, T2).
In all of the above solutions, the predicate fails if the list has an even number of elements. Since that's what your original solution does, I assumed that's what is required. If there is a specific requirement for even lists, that needs to be stated clearly.
I've been searching through the many existing Prolog questions on SO relevant to splitting but couldn't find one as generic as the one that I want. I'd like to point out that I've been able to split lists into lists of 2/3/4 elements by using 2/3/4 variables piped before a list variable. This question is different from that only because of its genericness.
So, my list will always contain N*N items, N being unknown beforehand(usually will vary from 4 to 36, yes N is also a perfect square). I want to split it into a list of N lists containing N items each because that'll allow me to treat it as a matrix, hence allowing to transpose and certain operations of that sort. I haven't really been able to get too far with the logic because I'm relatively new to declarative programming; please see below my incomplete(faulty) attempt:
listmodel(1,L):- L = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16].
size(L,N) :- length(L,N1), N is round(sqrt(N1)).
% add_tail(+Liste, +Element, -ResultantList)
add_tail([],L,[L]).
add_tail([X|L1],L2,[X|LI]):-add_tail(L1,L2,LI).
% partition the list containing N*N items into a list of N lists containing N elements each.
% part(+Liste, +Size, -ResultantList)
part([],_,DL).
part(L,N,DL) :-
length(P,N), % P(refix) initialized
append(P,S,L), % S(uffix) contains rest of L, using append in (-,-,+) mode
add_tail(DL,P,DL1), %add P(first N elements) as first element of DL.
part(S,N,DL1).
Now running ?- listmodel(1,L),size(L,N),part(L,N,DL). will produce DL=[] because that is what it gets initialized to in the first add_tail call in the part predicate. I can't seem to figure out how to store all elements in a list that's preserved through the recursion.
Any help/direction of any kind will be appreciated. I'm stuck here since over 23 hours 10 minutes now.
Thanks.
This should do it:
part([], _, []).
part(L, N, [DL|DLTail]) :-
length(DL, N),
append(DL, LTail, L),
part(LTail, N, DLTail).
Base case is first/last arguments are empty lists.
Recursive step takes a fresh list of N elements, takes the first N elements from L (which will be one of the items of the third argument) and calls recursively.
Want to combine versatility and favorable termination properties?
Use clpfd!
:- use_module(library(clpfd)).
First, we define
list_prefix_n_suffix/4.
list_prefix_n_suffix(Zs,Xs,N,Ys) is logically equivalent to both append(Xs,Ys,Zs), length(Xs,N) and length(Xs,N), append(Xs,Ys,Zs), but has better universal termination behavior than either1 one!
list_prefix_n_suffix(Zs, Xs, N, Ys) :-
list_prefix_n0_n_suffix(Zs, Xs, 0,N, Ys).
list_prefix_n0_n_suffix(Zs, Xs, N0,N, Ys) :-
zcompare(Order, N0, N),
rel_list_prefix_n0_n_suffix(Order, Zs, Xs, N0,N, Ys).
rel_list_prefix_n0_n_suffix(=, Ys, [], _,_, Ys).
rel_list_prefix_n0_n_suffix(<, [Z|Zs], [Z|Xs], N0,N, Ys) :-
N1 #= N0 + 1,
list_prefix_n0_n_suffix(Zs, Xs, N1,N, Ys).
Some sample queries for list_prefix_n_suffix/4:
?- list_prefix_n_suffix([a,b,c], Xs,-1, Ys).
false. % OK: too small
?- list_prefix_n_suffix([a,b,c], Xs, 0, Ys).
Xs = [], Ys = [a,b,c]. % succeeds deterministically
?- list_prefix_n_suffix([a,b,c], Xs, 4, Ys).
false. % OK: too big
?- list_prefix_n_suffix([a,b,c], Xs, N, Ys).
Xs = [] , N = 0, Ys = [a,b,c]
; Xs = [a] , N = 1, Ys = [b,c]
; Xs = [a,b] , N = 2, Ys = [c]
; Xs = [a,b,c], N = 3, Ys = []
; false. % terminates universally
Based upon above list_prefix_n_suffix/4 we define list_rows_width/3:
list_rows_width([], [], _N).
list_rows_width([E|Es0], [[R|Rs]|Rss], N) :-
list_prefix_n_suffix([E|Es0], [R|Rs], N, Es),
list_rows_width(Es, Rss, N).
Sample queries using list_rows_width/3:
?- list_rows_width([a,b,c,d,e,f], Rows, 4).
false. % OK: 6 is not divisible by 4
?- list_rows_width([a,b,c,d,e,f], Rows, 3).
Rows = [[a,b,c],[d,e,f]]. % succeeds deterministically
?- list_rows_width([a,b,c,d,e,f,g,h,i,j,k,l], Rows, N).
N = 1, Rows = [[a],[b],[c],[d],[e],[f],[g],[h],[i],[j],[k],[l]]
; N = 2, Rows = [[a, b],[c, d],[e, f],[g, h],[i, j],[k, l]]
; N = 3, Rows = [[a, b, c],[d, e, f],[g, h, i],[j, k, l]]
; N = 4, Rows = [[a, b, c, d],[e, f, g, h],[i, j, k, l]]
; N = 6, Rows = [[a, b, c, d, e, f],[g, h, i, j, k, l]]
; N = 12, Rows = [[a, b, c, d, e, f, g, h, i, j, k, l]]
; false. % terminates universally
Works just like it should!
Footnote 1: Without resorting to using alternative control-flow mechanisms like prolog-coroutining.
I have been brushing up on some Prolog recently. I kind of enjoy just coming up with random problems to try and solve and then working them out. This one is quite tough though, and I'm not one to give up on a problem that I have set out to solve.
The problem: I want to make a predicate that will have 2 predetermined lists, 2 numbers to swap, and then output the lists after the swapping is done.
Further Explanation: I made it a little harder on myself by wanting to find a specific unique number from list 1, and swapping this with a specific unique number from list 2 so that if I have 2 lists...
[7,2,7,8,5], and [1,2,3,8,7,9,8], and then give the predicate 2 numbers(Lets just say 8 and 7), then the number 8 and the number 7 will be swapped between the lists IF AND ONLY IF the number 8 is in the first list and the number 7 is in the second list. (It would disregard an 8 in the second list and a 7 in the first list).
Sample query with expected answer:
?- bothSwap([7,2,7,8,5],[1,2,3,8,7,9,8],8,7,X,Y).
X = [7,2,7,7,5], Y = [1,2,3,8,8,9,8].
I kind of got stuck at this point:
bothSwap([],L2,N1,N2,[],L2).
bothSwap(L1,[],N1,N2,L1,[]).
bothSwap([H1|T1],[H2|T2],N1,N2,X,Y) :- H1 == N1, H2 == N2, bothSwap(T1,T2,N1,N2,D1,D2), append(D1,[H2],X), append(D2,[H1],Y).
bothSwap([H1|T1],[H2|T2],N1,N2,X,Y) :- H1 == N1, H2 =\= N2, bothSwap([H1|T1],T2,N1,N2,D1,D2).
bothSwap([H1|T1],[H2|T2],N1,N2,X,Y) :- H1 =\= N1, H2 == N2, bothSwap(T1,[H2|T2],N1,N2,D1,D2).
Any bright minds out there willing to tackle this problem with me? :)
Imagine how easy this problem would be if we could just "wish" for a list to be split up at the occurrence of the desired element, like this:
?- splitsies([1,2,3,4,5,6,7,8], 4, Prefix, Suffix).
Prefix = [1, 2, 3],
Suffix = [5, 6, 7, 8] ;
Guess what? :) append/3 can do that:
% splitsies is true if X splits list into a prefix/suffix pair.
splitsies(List, X, Start, Finish) :-
append(Start, [X|Finish], List).
Now the problem seems pretty simple!
bothSwap(Left, Right, A, B, AfterLeft, AfterRight) :-
% break up the inputs
splitsies(Left, A, LPre, LPost),
splitsies(Right, B, RPre, RPost),
% glue together the outputs (note that A and B are switched)
splitsies(AfterLeft, B, LPre, LPost),
splitsies(AfterRight, A, RPre, RPost).
I wouldn't pretend that this solution is efficient… but it's so hot you better wear oven mitts when you type it in. Oh, and check this out:
?- bothSwap([7,2,7,8,5],[1,2,3,8,7,9,8], X, Y, [7,2,7,7,5], [1,2,3,8,8,9,8]).
X = 8,
Y = 7 ;
false.
Let's start, what you mean by swapping.
swap(X0,X, S0,S) :-
if_(X0 = S0, S = X, S = S0).
bothSwap0(Xs0, Ys0, X0,X, Xs,Ys) :-
maplist(swap(X0,X), Xs0,Xs),
maplist(swap(X,X0), Ys0,Ys).
if_( C_1, Then_0, Else_0) :-
call(C_1, Truth),
functor(Truth,_,0), % safety check
( Truth == true -> Then_0 ; Truth == false, Else_0 ).
=(X, Y, R) :- X == Y, !, R = true.
=(X, Y, R) :- ?=(X, Y), !, R = false. % syntactically different
=(X, Y, R) :- X \= Y, !, R = false. % semantically different
=(X, Y, R) :- R == true, !, X = Y.
=(X, X, true).
=(X, Y, false) :-
dif(X, Y).
Now you wanted a particular condition - it is not clear how to apply it. I see two interpretations:
bothSwap(Xs0, Ys0, X0,X, Xs,Ys) :-
memberd(X0, Xs0),
memberd(X, Ys0),
maplist(swap(X0,X), Xs0,Xs),
maplist(swap(X,X0), Ys0,Ys).
Which means that bothSwap/6 will fail should the two elements not occur in their respective list.
Another interpretation might be that you want that otherwise the lists remain the same. To express this (in a pure monotonic fashion):
bothSwap(Xs0, Ys0, X0,X, Xs,Ys) :-
if_( ( memberd_t(X0, Xs0), memberd_t(X, Ys0) ),
( maplist(swap(X0,X), Xs0,Xs), maplist(swap(X,X0), Ys0,Ys) ),
( Xs0 = Xs, Ys0 = Ys) ).
memberd_t(E, Xs, T) :-
list_memberd(Xs, E, T).
list_memberd([], _, false).
list_memberd([X|Xs], E, T) :-
if_(E = X, T = true, list_memberd(Xs, E, T) ).
','( A_1, B_1, T) :-
if_( A_1, call(B_1, T), T = false ).
Since Prolog is a descriptive language (that is, we describe what constitutes a solution and let Prolog work it out), If I understand your problem statement correctly, something like this ought to suffice:
both_swap(L1, L2, A, B, S1, S2 ) :- % to do the swap,
memberchk(A,L1) , % - L1 must contain an A
memberchk(B,L2) , % - L2 must contain a B
replace(L1,A,B,S1) , % - replace all As in L1 with a B
replace(L2,B,A,S2) % - replace all Bs in L2 with an A
. % Easy!
replace([],_,_,[]) . % if the list is empty, we're done.
replace([H|T],A,B,[S|Ss]) :- % otherwise...
( H = A -> S=B ; S=H ) , % - do the swap (if necessary),
replace(T,A,B,Ss) % - and recurse down
. % Also easy!
This replicates the implementation that uses splitsies/4
swap_two(A,B,C,D,E,F) :-
nth0(I1,A,C,L1),
dif(A,L1),
nth0(I2,B,D,L2),
dif(B,L2),
nth0(I1,E,D,L1),
nth0(I2,F,C,L2).
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].