我正在尝试编写一个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)的外观有关,但我不明白为什么? 提前致谢! :)
答案 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可以提供帮助,或者我们必须制定一个立即实例化战略的战略......