Prolog substitution

前端 未结 5 1278
囚心锁ツ
囚心锁ツ 2021-01-22 21:32

How can I replace a list with another list that contain the variable to be replaced. for example

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


        
相关标签:
5条回答
  • 2021-01-22 21:35

    Here's how you could proceed using if_/3 and (=)/3.

    First, we try to find a single Key in a list of pairs K-V. An extra argument reifies search success.

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

    Next, we need to handle "not found" cases:

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

    Last, we put it all together using the meta-predicate 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
    
    0 讨论(0)
  • 2021-01-22 21:38

    I find your code rather confused. For one thing, you have rep/3 and rep/4, but none of them have a list in the second position where you're passing the list of variable bindings. H1=H2 cannot possibly match a list, and that's the only rep/3 clause that examines the second argument. If this is a class assignment, it looks like you're a little bit behind and I'd suggest you spend some time on the previous material.

    The solution is simpler than you'd think:

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

    We're using member/2 to find a "variable binding" in the list (in quotes because these are atoms and not true Prolog variables). If it's in the list, Y is the replacement, otherwise we keep using X. And you see this has the desired effect:

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

    This could be made somewhat more efficient using "or" directly (and save us a choice point):

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

    See:

    ?- rep([x, d, e, z, x, z, p], [x=z, z=x, d=c], R).
    R = [z, c, e, x, z, x, p].
    
    0 讨论(0)
  • 2021-01-22 21:41

    If you use SWI-Prolog, with module lambda.pl found there : http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/lambda.pl you can write :

    :- use_module(library(lambda)).
    
    rep(L, Rep, New_L) :-
        maplist(\X^Y^(member(X=Z, Rep)
                  ->  Y = Z
                  ;   Y = X), L, New_L).
    
    0 讨论(0)
  • 2021-01-22 21:51

    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 .
    
    0 讨论(0)
  • 2021-01-22 21:51

    Let's improve this answer by moving the "recursive part" into meta-predicate 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)).
    

    To fill in the "missing bits and pieces", we define key_pair_t/3:

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

    Based on find_first_in_t/4 and key_pair_t/3, we can write assoc_key_mapped/3 like this:

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

    So, does the OP's use-case still work?

    ?- 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
    

    Building on 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).
    
    0 讨论(0)
提交回复
热议问题