假设我有以下内容:
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.
统一A
和B
。
如何定义exists/1
?
答案 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,以供一般使用。