prologprolog-setof

setof/3 does not seem to be removing duplicates


I'm attempting to find the complement of a list, given a list L1, and a universal list L2 with the following code:

complement(L1, L2, Res):-
    setof(X, (nth0(N, L2, X), not(member(X,L1))),Res).

However, my results include duplicates and are not given in list form as I'd prefer:

23 ?- complement([1,3], [-1,1,3,5,2,4,2,55,1,0], Res).
Res = [-1] ;
Res = [5] ;
Res = [2] ;
Res = [4] ;
Res = [2] ;
Res = [55] ;
Res = [0].

I figured it's probably due to Prolog's built-in backtracking but I'm not sure how to work around this to go about formatting the result correctly and getting it to remove any duplicate items in the result.


Solution

  • You get a warning from your code, about N being a singleton, and setof/3 requires that each variable 'universally quantified' get declared. So, you have two problems that go away together: replace nth0/3 by member/2:

    complement(L1, L2, Res):-
        setof(X, (member(X, L2), not(member(X, L1))), Res).
    

    edit

    symmetric difference could be

    symdiff(L1,L2,Diff) :-
        setof(X,(eldiff(L1,L2,X);eldiff(L2,L1,X)),Diff).
    eldiff(L1,L2,X) :-
        member(X,L1), \+member(X,L2).
    

    if L1 and L2 are ordered sets, much better to use ord_symdiff