2

I have to write the tr rule to translate all occurrences of a list element value to another value.

tr(A,B,L,M) if list M is the same as list L, except that every occurrence of A in L is replaced by B. For instance:

?- tr(1,2,[1,4,1,5],L).
L = [2, 4, 2, 5].

What I have so far:

tr(_, _, [], []).
tr(O, R, [O|T], [R|T2]) :- tr(O, R, T, T2).
tr(O, R, [H|T], [H|T2]) :- H \= O, tr(O, R, T, T2).

Is there a way to replace the tr(_, _, [], []). with tr(A,B,L,M). so that it uses the letters A,B,L,M?

false
  • 10,264
  • 13
  • 101
  • 209
Zast
  • 492
  • 2
  • 7
  • 22
  • 3
    And why would you want that? The rule `tr(_,_,[],[])` matches the case for empty list, and in such a way is clear to read. What would you gain by having 4 different variables there? – jpe Jun 03 '15 at 14:27
  • 1
    Ask yourself: "Which element can be replaced by another in an empty list?" – false Jun 03 '15 at 16:11
  • 2
    `tr(_, _, [], []).` is the most suitable way to express that particular rule. You could say, `tr(A, B, L, M) :- L = [], M = [].` but it's slightly less efficient and you'll get a singleton variable warning on `A` and `B`. Or you could say, `tr(_A, _B, L, M) :- L = [], M = [].` to get rid of the warnings but it's still not as clear as `tr(_, _, [], []).`. – lurker Jun 03 '15 at 16:28

2 Answers2

2

This pattern I learned from @false. I am currently learning but maybe you can also use some of it for your problem:

    tr(_,_,[],[]).
    tr(X,Y,[X|Xs],[Y|Rs]) :-
      tr(X,Y,Xs,Rs).
    tr(X,Y,[W|Ws],[W|Rs]) :-
      dif(X,W),
      tr(X,Y,Ws,Rs). 

Ex:

    ?- tr(1,2,[1,4,1,5],L).
    L = [2, 4, 2, 5] ;
    false.

    ?- tr(A,B,[1,4,1,5],[2, 4, 2, 5]).
    A = 1,
    B = 2 ;
    false. 
guest
  • 21
  • 1
  • Nice, now make it more compact with [`if_/3`](http://stackoverflow.com/a/27358600/772868) and [`maplist/3`](http://stackoverflow.com/a/6683502/772868)! One line with one goal is enough! – false Jun 04 '15 at 11:41
  • Try out and interpret the question: `?- tr(A,B,[C],[C]).` What does it mean? – false Jun 04 '15 at 11:44
1

maplist can do the job :

tr(A, B, L, M) :-
    maplist(tr_one(A,B), L, M).

tr_one(A,B,A,B).
tr_one(A,_,B,B) :-
    A \= B.

with same answers as @guest's queries.

joel76
  • 5,565
  • 1
  • 18
  • 22
  • Please consider using `dif/2` instead of `(\=)/2`. It helps preserve logical soundness when using non-ground Prolog terms. – repeat Jun 04 '15 at 14:56