5

假设我有以下内容:

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/3检查(parent(X, A), parent(X, B))结果列表是否为非空,但这并不能统一 A 或 B。


按照下面的建议使用setof/3是可行的,但我真的想找到一种方法将其合并到 的定义中sibling/2,而不必在问题中使用它。我真的很想能够做到以下几点:

?- sibling(diane, X).
X = charlie ;
X = eve ;
false.

或这个

?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

4

4 回答 4

5

在 Prolog 中使用 cut 是非常微妙的。大多数削减本质上是不正确的,但在某些情况下仍然有效。只要您想要一个答案,您就可以在这里使用删减。但既然你想要整套,那你就不走运了:你需要探索所有答案才能确定那套。

幸运的是,有一个优雅的捷径(双关语)setof/3:. 所以问

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

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

出于一般目的exists/1,定义

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

这允许使用存在量词。

于 2013-11-23T20:18:15.910 回答
2

这是一个仅使用cut 谓词 !/0的版本:

person(alice).
person(bob).
person(charlie).
person(diane).
person(eve).
parent(alice, charlie).
parent(bob, charlie).
parent(bob, diane).
parent(alice, diane).
parent(bob, eve).
parent(alice, eve).

sibling(X, Y) :-
  person(X),
  person(Y),
  X \= Y,
  sameparent(X, Y).

sameparent(X, Y) :-
  parent(P, X),
  parent(P, Y),
  !.

我们不将谓词放在!/0谓词中以允许在找到第一个公共父对象后sibling/2回溯到目标。sibling(X, Y)相反,我们将谓词!/0放在一个新的谓词中sameparent/2。我们还添加了一个person谓词,因为目标X \= Y需要它的XY被实例化。有关详细信息,请参阅此文档

一个问题:

?- sibling(diane, Y).
Y = charlie
Y = eve

另一个查询:

?- 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
于 2021-08-12T07:35:44.943 回答
1
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中,以供一般使用。

于 2013-11-23T23:35:33.107 回答
1

所以,正如在接受的答案中看到的,我们可以运行

?- setof(P, (parent(P,diane), parent(P,X), X\=diane), _).

或者

?- setof(P, (parent(P,diane), parent(P,X)), _), X\=diane.

得到你想要的。

因此,我们可以定义一个二元谓词“存在且A成立B”:

exists(A, B):- setof( A, B, _).

并将其用作

sibling_v1(A, B):- exists( P, (parent(P,A), parent(P,B)) ), B \= A.

或作为

sibling_v2(A, B):- exists( P, (parent(P,A), parent(P,B), B \= A) ).

定义所需的谓词。

但它仍然会遍历所有可能的路径以找出所有可能的解决方案(只报告一次)不然怎么能确定没有漏掉一些呢?

57 ?- exists( P, (parent(P,diane), parent(P,X), X\=diane)).
X = charlie ;
X = eve.

58 ?- exists( P, (parent(P,diane), parent(P,X), writeln([P,X]), X\=diane)).
[bob,charlie]
[bob,diane]
[bob,eve]
[alice,charlie]
[alice,diane]
[alice,eve]
X = charlie ;
X = eve.

59 ?- 
于 2021-08-20T09:36:14.037 回答