替换列表序言中的术语

时间:2012-04-02 16:59:40

标签: list replace prolog

我正在尝试编写一个prolog程序,它将把list,old_subterm和new_subterm作为输入,并返回一个新的列表,其中old_subterm的每个实例都已被new_subterm替换。 所以例如

| ?- sub_rep([h(A,g(x)),g(x),g(3)],g(x),p,T).
T = [h(A,p),p,g(3)] ? ;
no

所以我可以使用以下代码来使用基本列表:

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.

但是当我尝试使用更复杂的列表时,例如

?- replace(g(Y),h,[f(g(Y)),g(Y),g(1)],L).

我得到以下答案:

Y = 1,
L = [f(g(1)), h, h] ;
false.

这不是我想要的,因为我希望它能够回归:

? - L = [f(h),h,g(1)] ;
false.

我是prolog的新手,我可能错过了一些明显的东西,但我不明白为什么变量Y在这种情况下被实例化了?它在第二个例子中似乎不是问题。我想它与g(1)的外观有关,但我不明白为什么? 提前致谢! :)

2 个答案:

答案 0 :(得分:1)

对您的问题的第一次观察:列表长度相同!这听起来像是maplist/3的好候选人!

replace(A, B, As, Bs) :-
   maplist(repl(A,B), As, Bs).

对于问题的“递归”部分来说太多了。现在,我们必须定义repl/4。 以下是我对你想要的猜测:

repl(A, B, A0, B0) :-
   ( A == A0 -> B = B0 ; A0 = B0 ).

也许您想要一些其他测试而不是(==)/2

答案 1 :(得分:0)

你应该'爆炸'你的条款进行比较。

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

试验:

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

当模式中存在变量时,事情变得更加复杂:

?- replace(g(Y),h,[f(g(Y)),g(Y),g(1)],L).
Y = 1,
L = [f(h), h, h] ;

也许numbervars可以提供帮助,或者我们必须制定一个立即实例化战略的战略......