My program is intended to get rid of repeating elements in a list. I think its correct. I tried to make it work by putting cuts, but it didn't give correct results.
member(X,[X|_]). % If X is Head, it is a member
member(X,[_|T]) :- member(X,T). % If not, Recursively check the tail.
remove_duplicates([],[]).
remove_duplicates([H|T],R):-member(H,T),remove_duplicates(T,R).
remove_duplicates([H|T],[R|REM]):-remove_duplicates(T,REM).
However I am getting results: I = [_G2608, _G2611, _G2614|_G2615]
for input remove_duplicates([a,b,a,b,b,c],I)
.
Here is a version that is both pure and also more efficient in the sense that it does only need constant auxiliary space. The solutions posted so far require in the worst case space proportional to the size of the list in the first argument. But now to correctness:
?- remove_duplicates([A,B], Fs).
Here we ask:
How must
A
andB
look like to result in a listFs
that has no duplicates?
This question cannot be answered simply by stating the concrete Fs
, for this Fs
might be [A,B]
or [A]
should A
and B
be the same.
?- remove_duplicates([A,B],F).
A = B, F = [B]
; F = [A, B], dif(A, B).
And here is a solution to it. This definition requires the monotonic if_/3
and memberd_truth/3
defined in another answer.
remove_duplicates([], []).
remove_duplicates([E|Es], Fs0) :-
if_( memberd_truth(E, Es) , Fs0 = Fs , Fs0 = [E|Fs] ),
remove_duplicates(Es, Fs).
Personally, I would prefer a more relational name, like list_unique/2
or list_nub/2
as an allusion towards Haskell.