如何在没有回溯所有不同路径的情况下检查Prolog中是否存在任何满足条款?

时间:2013-11-23 19:56:01

标签: prolog prolog-cut prolog-setof

假设我有以下内容:

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.

现在,如果我要求Diane的兄弟姐妹,我会得到Charlie和Eve - 两次,一次通过Bob,一次通过Alice。我只想要每一次。
我不认为我可以在这里使用切割,因为这样可以完全阻止回溯。我喜欢什么,是一种检查是否存在任何的方法。

复述

sibling(A, B) :-
  ∃(parent(X, A), parent(X, B)),
  B \= A.

我尝试了几次切割,但都没有效果 我在(parent(X, A), parent(X, B))上尝试了findall并检查结果列表是否为非空,但是没有统一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.

统一AB

如何定义exists/1

2 个答案:

答案 0 :(得分:4)

在Prolog中使用cut非常精致。大多数削减基本上是不正确的,但仍然在某些情况下工作。如果你只需要一个答案,你可以在这里使用剪切。但是既然你想要整套,那你就不走运了:你需要探索所有答案来确定这一套。

幸运的是,有一个优雅的捷径:setof/3。所以问问

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

对于setof/3的这种用法,最后一个参数没有意义。它实际上是[t]

对于通用存在/ 1,定义

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

这允许使用存在性限定符。

答案 1 :(得分: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.

现在我想知道如何将其提取到方法exists / 1,以供一般使用。