1
votes

I have the following fact to remove all occurences of a element in a list. Although the output is correct, the element is just replaced for a blank space

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

When I call remover the output is :

remover(3,[1,2,3,4,3],Res)
Res = [1, 2, [4, []]]

I also have the following fact to remove only the first occurence but the output is the same from above

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

What am I doing wrong?

2

2 Answers

4
votes

You should not wrap T2 in a singleton list in the second clause, it should be:

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

In case you only need to remove the first occurrence, then you should not recurse from the moment you found that element:

remover( _, [], []).
remover( R, [R|T], T).
remover( R, [H|T], [H|T2]) :- H \= R, remover( R, T, T2).
2
votes

The solution by @WillemVanOnsem, derived from the OP code, uses term unification when comparing the element to be removed with the elements of the list (an alternative would be to use term equality). The solution works for ground terms. But can result in unexpected results when the terms are not ground. For example:

| ?- remover(a(_), [a(1), b(2), a(3), b(4)], List).

List = [b(2),a(3),b(4)] ? ;
no

Consider the following alternative definition of the remover/3 predicate:

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

With this solution, the query above gives:

| ?- remover(a(_), [a(1), b(2), a(3), b(4)], List).         

List = [b(2),b(4)] ? ;
no

Be sure to have a clear understanding of the semantics you want for the predicate.