Допустим, у меня есть следующее:
parent(alice, charlie).
parent(bob, charlie).
parent(bob, diane).
parent(alice, diane).
parent(bob, eve).
parent(alice, eve).
% people are siblings of each other if they share a parent
% and aren't the same person.
sibling(A, B) :-
parent(X, A),
parent(X, B),
B \= A.
Теперь, если я попрошу братьев и сестер Дианы, я получу Чарли и Еву дважды, один раз через Боба и один раз через Алису. Я хочу каждый раз только один раз.
Я не думаю, что здесь можно использовать отсечение, так как это полностью предотвратит откат. Чего я хотел бы, так это способа проверить, существует ли любой.
Перефразируя
sibling(A, B) :-
∃(parent(X, A), parent(X, B)),
B \= A.
Я попробовал несколько сокращений, но ни один из них не сработал.
Я попытался найти все на (parent(X, A), parent(X, B))
и проверить, не пуст ли полученный список, но это не объединяет A или B.
Использование setof/3, как предлагается ниже, работает, но я действительно хочу найти способ включить его в определение sibling/2 вместо того, чтобы использовать его в вопросе. Я действительно хотел бы иметь возможность сделать следующее:
?- sibling(diane, X).
X = charlie ;
X = eve ;
false.
% or this
?sibling(X, Y).
X = charlie,
Y = diane ;
X = charlie,
Y = eve ;
X = diane,
Y = charlie ;
X = diane,
Y = eve ;
X = eve,
Y = charlie ;
X = eve,
Y = diane ;
false.
Как я уже сказал ниже, у меня есть решение для этого конкретного случая. То, что я хотел бы, и то, за что я устанавливаю награду, является общим решением.
Вместо
sibling(A, B) :-
setof(D, X^(parent(X, A), parent(X, D)), Ds),
member(B, Ds),
B \= A.
я хотел бы сделать
sibling(A, B) :-
exists(X^(parent(X, A), parent(X, B))),
B \= A.
который объединяет A
и B
.
Как определить exists/1
?
setof
. Я также поэкспериментировал с несколькими приемами, чтобы не добавлять в результаты избыточные ответы, но зачастую они были более сложными, чем просто использованиеsetof
. - person lurker   schedule 24.11.2013