Usage of distinct still leading to duplicates

105 Views Asked by At

I'm new to prolog, and as I understand it, the purpose of 'distinct' is to weed out duplicates. However, this code block:

allpartsincity(City):-
    distinct((proj(Project, _, City), sppj(_, Part, Project, _), part(Part, _, _, _, _))),
    part(Part, Name, Color, Num, X),
    format('~w ~w ~w ~w ~w ~n', [Part, Name, Color, Num, X]),
    fail
    ;
    true.

yields the following:

?- allpartsincity(london).
p2 bolt green 17 paris 
p5 cam blue 12 paris 
p2 bolt green 17 paris 
p6 cog red 19 london 
p5 cam blue 12 paris 
true.

I'm not sure what I'm missing, but I'd appreciate if someone could point me in the right direction.

2

There are 2 best solutions below

5
CapelliC On

As you wrote it, the goal part/5 that provides displayed values is unrelated to the conjunction you asked for in distinct/1. If I understand your problem correctly, most likely you should use distinct/2 instead. Try for instance

allpartsincity(City):-
    distinct(part(Part, Name, Color, Num, X), (proj(Project, _, City), sppj(_, Part, Project, _), part(Part, _, _, _, _))),
    format('~w ~w ~w ~w ~w ~n', [Part, Name, Color, Num, X]),
    fail
    ;
    true.
0
false On

distinct/1 is a quite new predicate. It is only of relevance, if the incremental evaluation is of importance either because of infinite data or because (for some obscure reason) the exact order of answers is of relevance. OK, and maybe also because there are many redundant answers and the space to store them would be forbidding, but then a good setof/3 implementation might use a similar technique as well. In your case, you have just a data base of finitely many facts.

Since 19821, the classic predicate for your purpose is setof/3.

You did not give a minimal reproducible example. So I need to do some guessing. In any case, do trust the for printing.

city_part(City, CPart) :-
   setof(t, city_part0(City, CPart), _).

city_part0(City, part(Part, Name, Color, Num, X)) :-
   proj(Project, _A1, City),
   sppj(_A2, Part, Project, _A3),
   part(Part, Name, Color, Num, X).

You can avoid the intermediary predicate, but then the variable quantification will become cumbersome. I have given these variables already the names A1, A2, A3. These plus Project are only internal variables.

city_part(City, CPart) :-
   setof(t, A1^A2^A3^Project^
         (  CPart = part(Part, Name, Color, Num, X), 
            proj(Project, A1, City),
            sppj(A2, Part, Project, A3),
            part(Part, Name, Color, Num, X) 
         ), _).