2
votes

Assume that you want a predicate that replaces Number1 with Number2 in a list.
Of course it is trivial to write a recursive function for that, like:

replace(_,_,[],[]).
replace(N1,N2,[N1|T], [N2|NT]):-
    replace(N1,N2,T,NT).
replace(N1,N2,[H|T],[H|NT]):-
    replace(N1,N2,T,NT).

My question is if there is a way to do that with maplist/x (or similar meta-predicates).
One might use global variables to do that, like:

replace(N1,N2,L1,L2):-
    nb_setval(numbers,[N1,N2]),
    maplist(replace_in,L1,L2).

replace_in(N1,N2):-
    nb_getval(numbers,[N1,N2]).
    replace_in(X,X).

Another idea is to create a list of the same numbers List_of_N1 and List_of_N2 and pass them to maplist/4.
None of them look attractive to me, any ideas?

2

2 Answers

4
votes

As an aside: With your given definition, consider for example the apparently unintended second solution in:

?- replace(1, 4, [1,2,3], Ls).
Ls = [4, 2, 3] ;
Ls = [1, 2, 3] ;
false.

As to the actual question, consider:

replace(A, B, X, Y) :- ( X == A -> Y = B ; Y = X ).

Example query:

?- maplist(replace(1,4), [1,2,3], Ls).
Ls = [4, 2, 3].


For , I recommend a truly relational version which can be used in all directions:

replacement(A, B, A, B).
replacement(A, _, X, X) :- dif(A, X).

Example:

?- maplist(replacement(a,b), [X], Rs).
Rs = [b],
X = a ;
Rs = [X],
dif(X, a).
1
votes

How about this:

replace(N1,N2,L1,L2):-
    maplist(replace_in,[N1-N2-T|T], L1,L2).

replace_in(N1-N2-T, X, Y):-
  (X=N1 -> Y=N2 ; Y=X),
  (T=[N1-N2-L|L] ; T=[]).