Вы можете исключить один набор с помощью сравнения:
brother(X, Y) :-
son(X, P),
son(Y, P),
X \= Y, X @< Y.
?- brother(X, Y).
X = a,
Y = b ;
X = a,
Y = b ;
false.
Поскольку X и Y будут реализованы в обоих направлениях, требование, чтобы X было меньше Y, является хорошим способом сократить количество решений вдвое.
Ваша вторая проблема заключается в том, что X и Y являются братьями более чем по одному родителю. Самым простым решением здесь было бы сделать ваши правила более явными:
mother(a, d).
mother(b, d).
father(a, c).
father(b, c).
brother(X, Y) :-
mother(X, M), mother(Y, M),
father(X, F), father(Y, F),
X \= Y, X @< Y.
?- brother(X, Y).
X = a,
Y = b ;
false.
Этот метод очень специфичен для этой конкретной проблемы, но лежащие в его основе рассуждения не таковы: у вас было две копии, потому что a
и b
являются «братьями» по c
, а также по d
— Пролог был прав, создав это решение дважды, потому что была скрытая переменная. присваивается два разных значения.
Более элегантным решением, вероятно, было бы использование setof/3
для получения решений. Это может работать даже с вашим исходным кодом:
?- setof(X-Y, (brother(X, Y), X @< Y), Brothers).
Brothers = [a-b].
Недостатком этого подхода является то, что вы получаете список, а не Пролог, генерирующий различные решения, хотя вы можете исправить это поведение с помощью member/2
.
person
Daniel Lyons
schedule
23.02.2013