Search code examples
prolog

How to non-recursively replace "rep" element of a list with the previous element in Prolog


I am trying to duplicate the element of a list before the "rep" element, in a NON-recursive way. For example, I have the list

[1,2,rep,3,4,5]

and I want to end up with

[1,2,2,3,4,5]

or

[rep,1,2,3,4,5]

and want

[1,2,3,4,5]

So far I have:

element_repeat_non(List,Sol):-
  findall(X,element_inner(List,X),Sol).
        
element_inner(List,X):-
  member(X,List),
  not(X==rep).

This, however, only ignores the rep element and returns a list without it, giving the desired result in the case of

[rep,1,2,3,4,5]

but not in the case of

[1,2,rep,3,4,5]

I can't figure out how I can keep the previous element so I can replace the "rep" element. If possible, I would like to avoid using a condition check(if_then_else).

Any recommendations are welcome. Thanks in advance!


Solution

  • Considering that there can be at most one occurrence of the atom rep in the input list (as you have stated in your last comment), a possible solution is as follows:

    % repeat_previous(+List, -NewList)
    
      repeat_previous([rep|L], L).
      repeat_previous(L, L) :-
          not(append(_, [rep|_], L)).
      repeat_previous(L, S) :-
          append(Xs, [Y,rep|Ys], L),
          append(Xs, [Y,Y|Ys], S).
    

    Examples:

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