(Do read answers by repeat and Ludwig. Those are good answers)
Modified to remove both assumptions in old solution
conseq_swap(E1,E2,[E1,E2|R],[E2,E1|R]).
conseq_swap(E1,E2,[E2,E1|R],[E1,E2|R]).
conseq_swap(E1,E2,[A|RI],[A|RO]) :- conseq_swap(E1,E2,RI,RO).
Cuts ((!)/0
) are removed.
?- conseq_swap(a,e,[a,g,d,e,f],X).
false.
?- conseq_swap(d,e,[a,g,d,e,f],X).
X = [a, g, e, d, f] ;
false.
?- conseq_swap(d,e,[D,A,G,E,F],X), A=a,G=g,D=d,E=e,F=f.
false.
?- conseq_swap(d,e,[A,G,D,E,F],X), A=a,G=g,D=d,E=e,F=f.
A = a,
G = g,
D = d,
E = e,
F = f,
X = [a, g, e, d, f] ;
false.
For the case where there are many possible pairs to swap, it output all ways of swapping only once. The question assumes that there can only be one pair anyway.
?- conseq_swap(d,e,[a,g,d,e,d,e,f],X).
X = [a, g, e, d, d, e, f] ;
X = [a, g, d, d, e, e, f] ;
X = [a, g, d, e, e, d, f] ;
false.
Modified to remove assumption 2
If you want the query conseq_swap(a, e, [a, g, d, e, f], X).
to fail outright, remove the first two lines in the old solution, which allows the original list to end up as output when no swapping is performed.
Old solution (same output as the code in question)
This is the old solution written with the following assumptions:
- The input does not contain any unbounded variable.
- When no pair satisfying the condition is found, output the input list as-is, similar to what the code in the question does.
% Empty list gives empty list
conseq_swap(_,_,[],[]).
% List with single element gives back the same list
conseq_swap(_,_,[A],[A]) :- !.
% If we found the 2 items that need to be swapped, we can swap them.
% We don't check for the rest of the list, due to the
% assumption.
% The cut at the end signals that the rule below do not need to be checked.
conseq_swap(E1,E2,[E1,E2|R],[E2,E1|R]) :- !.
conseq_swap(E1,E2,[E2,E1|R],[E1,E2|R]) :- !.
% We recursively check the rest of the list and append the result.
conseq_swap(E1,E2,[A|RI],[A|RO]) :- conseq_swap(E1,E2,RI,RO).