2013-11-23 4 views
3

Скажем, у меня есть следующий:Как проверить, существует ли какое-либо условие statforying в Prolog без возврата по всем различным путям?

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. 

Я пытался несколько сокращений, но никто не работал.
Я попытался FindAll на (parent(X, A), parent(X, B)) и проверки, если результирующий список не пуст, но это не унифицировать А или В.


Использование setof/3, как предложено ниже работ, но я действительно хочу, чтобы найти способ включить его в определение брата/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?

+0

У меня был очень похожий случай, и я сделал то, что @false предложил с помощью 'setof'. Я также играл с несколькими методами, чтобы избежать лишних ответов в результатах, но они часто были более сложными, чем просто использование 'setof'. – lurker

ответ

4

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

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

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

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

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

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

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

+1

Да, это работает. И первый аргумент тоже не представляет интереса. 'setof (_, sibling (diane, S), _).' делает трюк. Тем не менее, я все еще пытаюсь найти способ включить его в определение родного брата. – SQB

+3

@SQB: '' '' '' '' в setof часто являются ошибкой (во втором аргументе). Да, он работает также с первым аргументом '_', но здесь вы изучаете некоторые довольно страшные пределы' setof/3'. Лучше держите в нем какой-то атом. 't' довольно идиоматично. – false

+1

Определите 'mysibling (X, Y): - setof (t, sibling (X, Y), _).' Это не так много, как это. О чем еще ты думал? – false

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

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

Смежные вопросы