私が次のものを持っているとしましょう:
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.
ダイアンの兄弟を尋ねると、チャーリーとイブが 2 回見つかります。1 回はボブから、もう 1 回はアリスからです。私はそれぞれ一度だけ欲しい。
バックトラックを完全に防ぐため、ここでカットを使用できるとは思いません。私が望むのは、存在するかどうかを確認する方法です。
言い換え
sibling(A, B) :-
∃(parent(X, A), parent(X, B)),
B \= A.
いくつかのカットを試しましたが、うまくいきませんでした。結果のリストが空でないかどうか
を試しfindall/3
てみましたが、それはAまたはBを統一しません.(parent(X, A), parent(X, 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.
A
とを一体化するものB
。
を定義するにはどうすればよいexists/1
ですか?