Как проверить, существует ли какое-либо статистическое предложение в Прологе, не возвращаясь по всем различным путям?

Допустим, у меня есть следующее:

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?


person SQB    schedule 23.11.2013    source источник
comment
У меня был очень похожий случай, и в итоге я сделал то, что предложил @false с setof. Я также поэкспериментировал с несколькими приемами, чтобы не добавлять в результаты избыточные ответы, но зачастую они были более сложными, чем просто использование setof.   -  person lurker    schedule 24.11.2013


Ответы (2)


Использование cut в Прологе очень деликатно. Большинство сокращений по сути неверны, но все же работают в определенных ситуациях. Вы можете использовать сокращение здесь, если вы хотите только один ответ. Но поскольку вам нужен весь набор, вам не повезло: вам нужно изучить все ответы, чтобы определить этот набор.

К счастью, для этого есть элегантный ярлык: setof/3. Так спроси

?- setof(t, sibling(diane,S),_).

При таком использовании setof/3 последний аргумент не представляет интереса. На самом деле это [t].

Для общего назначения существует/1, определите

exists(XGoal) :- setof(t, XGoal, _).

Это позволяет использовать экзистенциальные квалификаторы.

person false    schedule 23.11.2013
comment
Да, это работает. И первый аргумент тоже не представляет интереса. setof(_, sibling(diane, S), _). делает свое дело. Я все еще пытаюсь найти способ включить его в определение родного брата. - person SQB; 24.11.2013
comment
@SQB: _ в setof часто являются ошибкой (во втором аргументе). Да, это работает и с первым аргументом _, но здесь вы исследуете довольно пугающие ограничения setof/3. Лучше держи немного атома. t довольно идиоматично. - person false; 24.11.2013
comment
Дайте определение mysibling(X,Y) :- setof(t,sibling(X,Y),_). Это не более того. О чем еще вы думали? - person false; 27.11.2013
comment
Или: exists(XGoal) :- setof(t,XGoal,_) Теперь вы даже можете использовать квантификаторы. - person false; 27.11.2013
comment
Да, это работает! Я мог бы поклясться, что это не объединило, но это так. Должно быть, я где-то напутал. В любом случае, награда заработана :) - person SQB; 27.11.2013

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) :-
  setof(D, X^(parent(X, A), parent(X, D)), Ds),
  member(B, Ds),
  B \= A.

?- 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.

Теперь мне интересно, как извлечь это в метод exists/1 для общего использования.

person SQB    schedule 23.11.2013