Reputation: 149
I'm trying to write a prolog program that will take as input a list, an old_subterm and a new_subterm, and return a new list where every instance of old_subterm has been replaced with new_subterm. So for instance
| ?- sub_rep([h(A,g(x)),g(x),g(3)],g(x),p,T).
T = [h(A,p),p,g(3)] ? ;
no
So I can get this to work with basic lists, with the following code:
replace(E,S,[],[]).
replace(E,S,[E|T1],[S|T2]):-
replace(E,S,T1,T2).
replace(E,S,[H|T1],[H|T2]):-
E\=H,
replace(E,S,T1,T2).
%(here's some example input/output)
?- replace(b,e,[a,b,c],L).
L = [a, e, c] ;
false.
?- replace(f(Y),g(Y),[f(Y),1,2,f(Y)],L).
L = [g(Y), 1, 2, g(Y)] ;
false.
but when I try it with a more complicated list, such as
?- replace(g(Y),h,[f(g(Y)),g(Y),g(1)],L).
I get the following answer:
Y = 1,
L = [f(g(1)), h, h] ;
false.
which is not what I'm looking for, since I'm hoping for it to return:
? - L = [f(h),h,g(1)] ;
false.
I'm new to prolog, and I'm probably missing something obvious, but I don't understand why the variable Y is getting instantiated in this case? It doesn't appear to be a problem in the second example. I imagine it has something to do with the appearance of g(1), but I don't understand why? Thanks in advance! :)
Upvotes: 1
Views: 1099
Reputation: 10102
A first observation on your problem: The lists are of same length! This sounds like a good candidate for maplist/3
!
replace(A, B, As, Bs) :-
maplist(repl(A,B), As, Bs).
So much for the "recursive" part of your problem. Now, we have to define repl/4
.
Here is my guess about what you want:
repl(A, B, A0, B0) :-
( A == A0 -> B = B0 ; A0 = B0 ).
Maybe you want some other test in stead of (==)/2
.
Upvotes: 1
Reputation: 60014
You should 'explode' your terms for comparison.
replace(_, _, [], []).
replace(E, S, [X|T1], [Y|T2]):-
replace_term(E, S, X, Y),
!, replace(E, S, T1, T2).
replace(E,S, [H|T1], [H|T2]):-
replace(E,S,T1,T2).
replace_term(E, S, E, S) :- !.
replace_term(E, S, T, R) :-
T =.. [F|As], % explode
replace(E, S, As, Gs),
R =.. [F|Gs]. % reassemble
test:
?- replace(a,b,[a(a),b,c],L).
L = [a(b), b, c] ;
false.
?- replace(g(y),h,[f(g(y)),g(y),g(1)],L).
L = [f(h), h, g(1)] .
when there are variables in pattern, things get more complex:
?- replace(g(Y),h,[f(g(Y)),g(Y),g(1)],L).
Y = 1,
L = [f(h), h, h] ;
Perhaps numbervars can help, or we must devise a strategy that instantiate at once the vars...
Upvotes: 0