replacing list elements in sicstus prolog - list

I am writing a Prolog predicate that takes arguments (A1, A2, L1, L2) and succeeds if all occurences of A1 within L1 have been changed to A2 in L2.
i.e.:
| ?- replace(a, b, [a], X).
X = [b]
Here's what I've written:
replace(Orig,_,[Other],[Other]) :- Other \== Orig.
replace(Orig,Repl,[Orig],[Repl]).
replace(Orig,Repl,[Other|T1],[Other|T2]) :- Other \== Orig, replace(Orig,Repl,T1,T2).
replace(Orig,Repl,[Orig|T1],[Repl|T2]) :- replace(Orig,Repl,T1,T2).
Now, this works, but seems a bit unelegant. Can there be a more elegant solution?
Thanks.

SICStus Prolog features dif/2 so you can define the relation in a pure manner like so:
replacement(A, B, X, Y) :-
( A = X, B = Y
; dif(A,X), X = Y
).
maplist_replacement([], [], _, _).
maplist_replacement([X|Xs], [Y|Ys], A, B) :-
replacement(A, B, X, Y),
maplist_replacement(Xs, Ys, A, B).
?- maplist_replacement([1,2,3],Ys, 1,x).
Ys = [x,2,3].
?- maplist_replacement([X,Y],[X,Y],A,B).
B = A, X = A, Y = A
; B = A, X = A, dif(A,Y)
; B = A, Y = A, dif(A,X)
; dif(A,X), dif(A,Y).
The last query corresponds to the question: What must A and B look like such that a two element list will remain the same? There are four answers:
A, B, X, and Y are all the same.
A, B, and X are the same, and Y is different.
A, B, and Y are the same, and X is different.
X and Y are both different to A.
In newer versions of SICStus, maplist/3 is in a library, however the definition is not entirely monotonic.
For a definition of maplist/3 see Prolog map procedure that applies predicate to list elements.

What about:
replace(A, B, X, Y) :- ( X == A -> Y = B ; Y = X ).
Example:
?- maplist(replace(1,x), [1,2,3], Ls).
Ls = [x, 2, 3].
It is easy to unfold the maplist/3 call into a recursive predicate if you prefer that.

Related

Convert complex term to List of lists and then back to term with modified functor

you can use =.. to convert simple terms.
?- x(a,b,c) =.. A.
A = [x, a, b, c].
what about complex terms :
x(a,b(c,d)) ==> [x,a,[b,c,d]]
x(a,b(c,q(d))) ==> [x,a,[b,c,[q,d]]]
then as separate task i want to re-generate the terms with changed functor :
x(a,b(c,d)) ==> [x,a,[b,c,d]] ==> y(a,f(c,d))
deep_univ(X, Y) :-
X =.. [H|Rest],
(
Rest = []
-> Y = X
; maplist(deep_univ, Rest, ExpRest),
Y=[H|ExpRest]
).
rev_univ([H|Rest], Y) :-
maplist(rev_univ, Rest, RestT),
Y =.. [H|RestT].
rev_univ(H, H) :- \+ is_list(H).
?- T=x(a,b,c(d,e(f)), j), deep_univ(T, X), rev_univ(X, Y).
T = Y, Y = x(a, b, c(d, e(f)), j),
X = [x, a, b, [c, d, [e, f]], j]

Comparing lists and elements

I am trying to compare and retrieve values from corresponding lists. My Predicate is correspond_elements(V1, Xs, V2, Ys), where I expect the following behavior:
?- correspond_elements(a, [a,b,b,a], X, [1,2,3,4]).
X = 1;
X = 4.
Where V1 is checked in the first list Xs, and the corresponding values in Ys are given to V2 to return. So far I have this:
% checks if the argument is a list
is_list([]).
is_list([_|T]) :-
is_list(T).
% predicate
correspond_elements(V1, [X|Xs], V2, [Y|Ys]) :-
is_list([X|Xs]),
is_list([Y|Ys]),
( V1 == X ->
V2 is Y
;
correspond_elements(V1, Xs, V2, Ys)
).
Which only gets the first value:
?- correspond_elements(a, [a,b,b,a], X, [1,2,3,4]).
X = 1.
I know that once the -> clause becomes true, then anything after the ; is not executed. It is clear that my code will only get the first answer it finds for X and stop, but I am unsure of how to keep recursing through the list and return all the possible answers for X, even after the first answer has been found.
As you have found out yourself, the if-then-else of Prolog A -> B; C will check the condition A, and if true it will execute B (and not C). Otherwise it will execute C (and not B).
You however want to execute C as an additional option in case A is true. This can be done, by transforming:
foo(Some,Parameters) :-
A
-> B
; C.
into:
foo(Some,Parameters) :-
A,
B.
foo(Some,Parameters) :-
C.
Since now A works as a guard for B, but regardless whether A succeeds or fails, Prolog will backtrack and execute the second foo/2 clause.
If we remove the is_list(..) predicates (which are a bit verbose in my opinion), we can produce the predicate:
correspond_elements(X, [X|_], Y, [Y|_]).
correspond_elements(V1, [_|Xs], V2, [_|Ys]) :-
correspond_elements(V1, Xs, V2, Ys).
We do not have to write the condition V1 == X here, since we used unification in the head for this. Because we use unification, it is V1 = X (one equation sign), so that means we can use the predicate in a more multi-directional way.
Querying the elements in the second list X:
?- correspond_elements(a, [a,b,b,a], X, [1,2,3,4]).
X = 1 ;
X = 4 ;
false.
Querying all tuples A and X of both lists (some sort of "zip"):
?- correspond_elements(A, [a,b,b,a], X, [1,2,3,4]).
A = a,
X = 1 ;
A = b,
X = 2 ;
A = b,
X = 3 ;
A = a,
X = 4 ;
false.
Obtain the elements in the first list:
?- correspond_elements(A, [a,b,b,a], 1, [1,2,3,4]).
A = a ;
false.
Generate a list such that 1 is in the list:
?- correspond_elements(A, [a,b,b,a], 1, L).
A = a,
L = [1|_G1285] ;
A = b,
L = [_G1284, 1|_G1288] ;
A = b,
L = [_G1284, _G1287, 1|_G1291] ;
A = a,
L = [_G1284, _G1287, _G1290, 1|_G1294] .

Prolog - Finding adjacent elements in a list

I'm trying to define a predicate adjacent(X, Y, Zs) that is true if X and Y are adjacent in a list. My code is currently this:
adjacent(_, _, []).
adjacent(X, Y, [X, Y|Tail]) :-
adjacent(X,Y, Tail).
It works for the basic case of adjacent(c, d, [a, b, c, d, e]), but due to the base case, every other case returns true as well, and I'm stuck on that.
The other problem is that if X is not equal to the first part of the list's head, then it skips past both X and Y and goes to the next 'X'; e.g., if c isn't equal to a, then it skips past both a and b and checks if c is equal to c. This is problematic when, for example, the list is
[a, c, d, e]
because it ends up never checking c (I believe).
I'm pretty lost on how to reconcile the two issues and turn my logical understanding of what needs to occur into code.
EDIT: Thanks to Christian Hujer's answer, my base case mistake has been corrected, so now I'm just stuck on the second issue.
In the original solution attempt:
adjacent(_, _, []).
adjacent(X, Y, [X, Y|Tail]) :-
adjacent(X,Y, Tail).
As #ChristianHujer points out, the first clause should not be there because it isn't true. The empty list should have no adjacent elements.
The second clause is also problematic. It shows that X and Y are adjacent in the list, but then recurses and doesn't just succeed. A proper clause should be:
adjacent(X, Y, [X,Y|_]).
Which says that X and Y are adjacent in the list if they're the first two elements in the list, regardless of what the tail is. This also forms a proper base case. Then your general, recursive clause should take care of the rest of the cases:
adjacent(X, Y, [_|Tail]) :-
adjacent(X, Y, Tail).
This says that X and Y are adjacent in [_|Tail] if they're adjacent in Tail. This takes care of the second problem you were encountering.
Thus, the whole solution would be:
adjacent(X, Y, [X,Y|_]).
adjacent(X, Y, [_|Tail]) :-
adjacent(X, Y, Tail).
This will succeed as many times as X and Y appear together, in that order, in the list.
This is also naturally solvable with a DCG (although #repeat's append/3 based solution is more concise):
adjacent(X, Y) --> ..., [X, Y], ... .
... --> [] | [_], ... .
adjacent(X, Y, L) :- phrase(adjacent(X, Y), L).
| ?- adjacent(b, c, [a,b,c,d]).
true ? a
(1 ms) no
| ?-
I think your base case is wrong. In your situation, you want recursion to terminate with a false predicate, not with a true predicate. And it's logical: In an empty list, there are no adjacent elements. Never.
In this answer we try to keep it simple—by building on append/3:
adjacent(E0, E1, Es) :-
append(_, [E0,E1|_], Es).
Sample query:
?- adjacent(X, Y, [a,b,c,d,e]).
X = a, Y = b ;
X = b, Y = c ;
X = c, Y = d ;
X = d, Y = e ;
false.
The auxiliary predicate adjacent_/5 always "lags behind" by exactly two (list items):
adjacent(X0, X1, [E0,E1|Es]) :-
adjacent_(Es, E0, E1, X0, X1).
adjacent_([], E0, E1, E0, E1).
adjacent_([E2|Es], E0, E1, X0, X1) :-
if_(E0+E1 = X0+X1,
true,
adjacent_(Es, E1, E2, X0, X1)).
Using SWI-Prolog we run:
?- set_prolog_flag(double_quotes, chars).
true.
?- adjacent(a, b, "abab").
true.
?- adjacent(b, c, "abcd").
true.
?- adjacent(X, Y, "abcd").
X = a, Y = b
; X = b, Y = c
; X = c, Y = d.
Edit
The corrected definition of adjacent_/5 gives right answers for the following queries, too:
?- adjacent(X, X, [A,B,C]).
X = A, A = B
; X = B, B = C, dif(f(C,C),f(A,A)).
?- adjacent(a, X, "aab").
X = a
; X = b.
?- adjacent(a, b, "aab").
true.
Here is a definition that I believe is in the long term preferable to #repeat's solution:
adjacent(X0, X1, [E0,E1|Es]) :-
adjacent_(Es, E0, E1, X0, X1).
adjacent_([], E0, E1, E0, E1).
adjacent_([E2|Es], E0, E1, X0, X1) :-
if_(( E0 = X0, E1 = X1 ),
true,
adjacent_(Es, E1, E2, X0, X1)).
Using a reified and:
','(A_1, B_1, T) :-
if_(A_1, call(B_1, T), T = false).
;(A_1, B_1, T) :-
if_(A_1, T = true, call(B_1, T)).

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

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