Короче говоря : Prolog отслеживает все переменные, которые выходят из цели, включая все равно (_
).
Проблема в том, что вы вводите свободные переменныездесь, которые не различны.Действительно, как указано в документации distinct/1
[swi-doc] .Выше функционально эквивалентно:
distinct(Goal) :-
findall(Goal, Goal, List),
list_to_set(List, Set),
member(Goal, Set).
Теперь, если мы сделаем простой вызов с sibling(P, _)
, мы получим:
?- Goal = sibling(P, _), distinct(Goal).
Goal = sibling(joe, mary),
P = joe ;
Goal = sibling(joe, bob),
P = joe.
или с цельюс логическим «или»:
?- Goal = (sibling(P, _); sibling(_, P)), distinct(Goal).
Goal = (sibling(joe, mary);sibling(_4908, joe)),
P = joe ;
Goal = (sibling(joe, bob);sibling(_4908, joe)),
P = joe ;
Goal = (sibling(mary, _4904);sibling(joe, mary)),
P = mary ;
Goal = (sibling(bob, _4904);sibling(joe, bob)),
P = bob.
Итак, как вы можете видеть, Goal
объединяется дважды: один раз с sibling(joe, mary)
и один раз с sibling(joe, bob)
.Фильтр уникальности не будет иметь никакого эффекта, так как mary
- это не то же самое, что bob
.
Однако мы можем определить здесь предикат-помощник, чтобы избавиться от этих переменных, например:
person(P) :-
sibling(P, _).
person(P) :-
sibling(_, P).
и затем мы можем запросить с помощью:
?- Goal = person(P), distinct(Goal).
Goal = person(joe),
P = joe ;
Goal = person(mary),
P = mary ;
Goal = person(bob),
P = bob.
или без использования переменной Goal
:
?- distinct(person(P)).
P = joe ;
P = mary ;
P = bob.