如果只有一个合乎逻辑的答案,如何询问序言

How to ask prolog if there's only one logical answer

我试图在 Prolog 中提出一个查询,我在其中询问是否存在 x^2=25 的值。但是,我只想 return yes 如果在知识库中只有一种情况 x^225.

我的知识库中有这个:

squared(5,25) 
squared((-5),25)

我希望程序 return no 因为 x 有两个答案,其中 x^2 =25,当我只想要一个。

到目前为止我有这个:

squared(x,25),squared(x,25), x=x.

您可以按如下方式使用forall/2

squared(X, 25), forall(squared(Y, 25), X = Y).

仅当 squared(X, 25) 的所有解都具有相同的值时,此查询才会成功。

详细一点:

squared(X, 25),                 % we have a single solution, X
forall(squared(Y, 25), X = Y).  % we are asserting all solutions are equal to X

如果你不熟悉forall/2:

forall(Condition, Action) succeeds if for all alternative bindings of Condition, Action can be proven. It is equivalent to \+ (Condition, \+ Action).

因此这适用于具有多重性 > 1 根的谓词(这可能不是您想要的,在这种情况下 findall 可能会有所帮助)。以下将确保您只有一个根:

findall(X, squared(X, 25), [_]).

让我们看一个例子 X^2 = 0,它在 0 处有双根:

squared(0, 0).
squared(0, 0).

所以你将拥有:

|?- findall(X, squared(X, 0), [_]).               % check for exactly one root
no

|?- squared(X, 0), forall(squared(Y, 0), X = Y).  % same root with any multiplicity
X = 0 ? 
yes

序言中的变量也以大写字母(或 _)开头。

编辑:更优化的搜索

squared(X, 25), !, forall(squared(Y, 25), X = Y).

squared(X, 25) 之后的剪切确保我们只遍历所有根一次。如果 forall 迭代失败,则存在 Ysquared(Y, 25)Y \= X。所以我们不需要检查不同的 any different X.