1

I am writing a Prolog predicate that takes arguments (A1, A2, L1, L2) and succeeds if all occurences of A1 within L1 have been changed to A2 in L2.

i.e.:

| ?- replace(a, b, [a], X).
X = [b]

Here's what I've written:

replace(Orig,_,[Other],[Other]) :- Other \== Orig.
replace(Orig,Repl,[Orig],[Repl]).
replace(Orig,Repl,[Other|T1],[Other|T2]) :- Other \== Orig, replace(Orig,Repl,T1,T2).
replace(Orig,Repl,[Orig|T1],[Repl|T2]) :- replace(Orig,Repl,T1,T2).

Now, this works, but seems a bit unelegant. Can there be a more elegant solution?

Thanks.

false
  • 10,264
  • 13
  • 101
  • 209
Alexander
  • 363
  • 4
  • 15

2 Answers2

2

SICStus Prolog features dif/2 so you can define the relation in a pure manner like so:

replacement(A, B, X, Y) :-
   ( A = X, B = Y
   ; dif(A,X), X = Y
   ).

maplist_replacement([], [], _, _).
maplist_replacement([X|Xs], [Y|Ys], A, B) :-
   replacement(A, B, X, Y),
   maplist_replacement(Xs, Ys, A, B).
?- maplist_replacement([1,2,3],Ys, 1,x).
   Ys = [x,2,3].
?- maplist_replacement([X,Y],[X,Y],A,B).
   B = A, X = A, Y = A
;  B = A, X = A, dif(A,Y)
;  B = A, Y = A, dif(A,X)
;  dif(A,X), dif(A,Y).

The last query corresponds to the question: What must A and B look like such that a two element list will remain the same? There are four answers:

  1. A, B, X, and Y are all the same.

  2. A, B, and X are the same, and Y is different.

  3. A, B, and Y are the same, and X is different.

  4. X and Y are both different to A.

In newer versions of SICStus, maplist/3 is in a library, however the definition is not entirely monotonic. For a definition of maplist/3 see Prolog map procedure that applies predicate to list elements.

false
  • 10,264
  • 13
  • 101
  • 209
1

What about:

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

Example:

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

It is easy to unfold the maplist/3 call into a recursive predicate if you prefer that.

mat
  • 40,498
  • 3
  • 51
  • 78
  • maplist isn't in Sicstus, unfortunately. edit: hm, apparently Sicstus should have it, but somehow the Sicstus on my machine doesn't. bummer. :) – Alexander Mar 31 '13 at 20:53
  • Recent versions definitely have it. It's also easy to get a direct recursive definition, you only need to add two lines of code to the replace/4 predicate above and change `X` and `Y` to talk about lists instead of individual elements. – mat Mar 31 '13 at 21:03