1

如何将一个列表替换为另一个包含要替换的变量的列表。例如

rep([x, d, e, z, x, z, p], [x=z, z=x, d=c], R).
R = [z, c, e, x, z, x, p]

x 到 z 和 z 被替换后不会改变。

到目前为止,我只做了一个没有清单的

rep([], _, []).
rep(L1, H1=H2, L2) :-
   rep(L1, H1, H2, L2).

rep([],_,_,[]).
rep([H|T], X1, X2, [X2|L]) :-
   H=X1,
   rep(T,X1,X2,L),
   !.
rep([H|T],X1,X2,[H|L]) :-
   rep(T,X1,X2,L).
4

5 回答 5

1

You should attempt to keep the code simpler than possible:

rep([], _, []).
rep([X|Xs], Vs, [Y|Ys]) :-
   ( memberchk(X=V, Vs) -> Y = V ; Y = X ),
   rep(Xs, Vs, Ys).

Of course, note the idiomatic way (thru memberchk/2) to check for a variable value.

Still yet a more idiomatic way to do: transforming lists it's a basic building block in several languages, and Prolog is no exception:

rep(Xs, Vs, Ys) :- maplist(repv(Vs), Xs, Ys).
repv(Vs, X, Y) :- memberchk(X=V, Vs) -> Y = V ; Y = X .
于 2013-03-26T17:47:28.097 回答
1

如果你使用 SWI-Prolog,在那里找到模块 lambda.pl:http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/lambda.pl你可以写:

:- use_module(library(lambda)).

rep(L, Rep, New_L) :-
    maplist(\X^Y^(member(X=Z, Rep)
              ->  Y = Z
              ;   Y = X), L, New_L).
于 2013-03-26T17:12:18.753 回答
1

让我们通过将“递归部分”移动到来改进这个答案 find_first_in_t/4

:- meta_predicate find_first_in_t(2,?,?,?).
find_first_in_t(P_2,X,Xs,Truth) :-
   list_first_suchthat_t(Xs,X,P_2,Truth).

list_first_suchthat_t([]    ,_, _ ,false).
list_first_suchthat_t([E|Es],X,P_2,Truth) :-
   if_(call(P_2,E),
       (E=X,Truth=true),
       list_first_suchthat_t(Es,X,P_2,Truth)).

为了填补“缺失的点点滴滴”,我们定义key_pair_t/3

key_pair_t(Key,K-_,Truth) :-
   =(Key,K,Truth).

基于find_first_in_t/4and key_pair_t/3,我们可以assoc_key_mapped/3这样写:

assoc_key_mapped(Assoc,Key,Value) :-
   if_(find_first_in_t(key_pair_t(Key),_-Value,Assoc),
       true,
       Key=Value).

那么,OP 的用例是否仍然有效?

?- maplist(assoc_key_mapped([x-z,z-x,d-c]), [x,d,e,z,a,z,p], Rs).
Rs = [z,c,e,x,a,x,p].                            % OK. same result as before

建立在find_first_in_t/4

memberd_t(X,Xs,Truth) :-                        % memberd_t/3
   find_first_in_t(=(X),_,Xs,Truth).

:- meta_predicate exists_in_t(2,?,?).           % exists_in_t/3
exists_in_t(P_2,Xs,Truth) :-
   find_first_in_t(P_2,_,Xs,Truth).
于 2015-07-23T14:07:09.423 回答
1

以下是如何继续使用if_/3and (=)/3

首先,我们尝试Key在 pair 列表中找到一个K-V。一个额外的参数具体化了搜索成功。

pairs_key_firstvalue_t([]       ,_  ,_    ,false).
pairs_key_firstvalue_t([K-V|KVs],Key,Value,Truth) :-
   if_(K=Key,
       (V=Value, Truth=true),
       pairs_key_firstvalue_t(KVs,Key,Value,Truth)).

接下来,我们需要处理“未找到”的情况:

assoc_key_mapped(Assoc,Key,Value) :-
   if_(pairs_key_firstvalue_t(Assoc,Key,Value),
       true,
       Key=Value).

将它们放在一起maplist/3

?- maplist(assoc_key_mapped([x-z,z-x,d-c]), [x,d,e,z,a,z,p], Rs).
Rs = [z,c,e,x,a,x,p].                       % OK, succeeds deterministically
于 2015-07-23T12:11:14.577 回答
0

我发现您的代码相当混乱。一方面,您有rep/3and rep/4,但它们都没有在您传递变量绑定列表的第二个位置的列表。H1=H2不可能匹配列表,这rep/3是检查第二个参数的唯一子句。如果这是一个课堂作业,看起来你有点落后,我建议你花一些时间在以前的材料上。

解决方案比您想象的要简单:

rep([], _, []).
rep([X|Xs], Vars, [Y|Rest]) :-    member(X=Y, Vars), rep(Xs, Vars, Rest).
rep([X|Xs], Vars, [X|Rest]) :- \+ member(X=_, Vars), rep(Xs, Vars, Rest).

我们member/2用来在列表中查找“变量绑定”(用引号括起来,因为这些是原子而不是真正的 Prolog 变量)。如果它在列表中,则 Y 是替换,否则我们继续使用 X。您会看到这具有预期的效果:

?- rep([x, d, e, z, x, z, p], [x=z, z=x, d=c], R).
R = [z, c, e, x, z, x, p] ;
false.

这可以通过直接使用“或”来提高效率(并为我们节省一个选择点):

rep([], _, []).
rep([X|Xs], Vars, [Y|Ys]) :- 
  (member(X=Y, Vars), ! ; X=Y), 
  rep(Xs, Vars, Ys).

看:

?- rep([x, d, e, z, x, z, p], [x=z, z=x, d=c], R).
R = [z, c, e, x, z, x, p].
于 2013-03-26T14:46:32.193 回答