2

The question was to create a replace/4 predicate that would replace a certain element (X) from the first list with another element (Y) like x and finally store it into the last argument, a new list. I know there is obviously something wrong with my base case (?), but I can't seem to figure it out. When I trace this code, it starts of normal, but after the first list is empty, it starts adding anonymous variables. Please have mercy, I'm new to Prolog.

replace([], _, _, []).
replace([H|T], X, Y, N):-
  H = X,
  append(N, [Y], NL),
  replace(T, X, Y, NL).
replace([H|T], X, Y, N):-
  H \= X,
  append(N, [H], NL),
  replace(T, X, Y, NL).
Boomer
  • 383
  • 2
  • 4
  • 15
  • You append the wrong way... It should be `append(NL, [Y], N)`, and `append(NL, [H], N)`. But that will still be inefficient, and furthermore you do not need `append/3` at all. – Willem Van Onsem Sep 26 '17 at 19:15
  • I figured out there might indeed be an efficient way of doing all this. But I cant seem to think of one that works. – Boomer Sep 26 '17 at 19:30
  • I changed it into `append([Y], NL, N)` and `append([H], NL, N)`. It works now, but I'd still want to know what the more efficient way would be. – Boomer Sep 26 '17 at 19:33

1 Answers1

3

A simple more efficient solution without append/3 would be:

replace([], _, _, []).
replace([X|T], X, Y, [Y|T1]):-replace(T, X, Y, T1).
replace([H|T], X, Y, [H|T1]):-dif(X,H), replace(T, X, Y, T1).

Note that it is much better to use predicate dif/2 instead of \= operator (it has more relational behavior: Just test dif(X,Y). and X\=Y. with X,Y unbound variables to see the difference).

Example:

?- replace([2,4,5,7,8,2,3,4],2,12,L).
L = [12, 4, 5, 7, 8, 12, 3, 4] ;
false.

Another solution would be using DCG:

replace([],_,_) -->[].
replace([X|T],X,Y) --> [Y],replace(T,X,Y).
replace([H|T],X,Y) --> [H],{dif(H,X)},replace(T,X,Y).

final_replace(In_L,X,Y,Out_L):- phrase(replace(In_L,X,Y),Out_L).

Example:

?- final_replace([2,4,5,7,8,2,3,4],2,12,L).
L = [12, 4, 5, 7, 8, 12, 3, 4] ;
false.
coder
  • 12,832
  • 5
  • 39
  • 53
  • `dif/2` is fantastic, but it is *not* ISO; see [this answer from @false](https://stackoverflow.com/a/13770020/812818). – Daniel Lyons Sep 26 '17 at 20:52