Prolog-如何执行返回空列表而不是失败的集合



我需要一个满足目标的有序对象列表。setof负责排序,但在没有对象满足Goal时失败。我想像findall那样返回一个空列表。

这是可行的,但有没有一种方法可以在不削减成本的情况下实现这一点?我正在使用SWI Prolog。

setof(Object, Goal, List), !; List = [].

首先,

..., ( setof(Object, Goal, List), ! ; List = [] ), ...

不起作用,正如你所建议的。对于List = [],它总是成功的,并且它只显示setof/3的第一个答案。但setof/3可能会产生几个答案。在任何Prolog中工作的通用方法是:

..., ( + Goal -> List = [] ; setof(Object, Goal, List) ), ...

许多实现为此提供了特定于实现的控制结构,从而避免了Goal被调用两次。例如if/3(SICStus、YAP)或(*->)/2(SWI、GNU):

..., if( setof(Object, Goal, ListX), ListX = List, List = [] ), ...
..., ( setof(Object, Goal, ListX) *-> ListX = List ; List = [] ), ...

新的变量ListX对于List已经实例化的(公认罕见的)情况是必要的。

请注意,其他两个答案并不能完全满足您的要求

(setof(Object, Goal, List) ; List = [])

也会起作用(集合本身是确定性的)。

为了确保摆脱选择点,我们需要一个更详细的

(setof(Object, Goal, List) -> true ; List = [])

编辑目前,我的回答显然是错误的,或者至少非常不完整。在虚假评论和回答后,我建议

setof(Object, Goal, List) *-> true ; List = [].

如果您不需要潜在的不确定性或setof的可变量化特征,您可以使用findall/3。这是确定性的,不会失败:

?- findall(X, fail, Xs).
Xs = []
yes

然后,您可以使用sort/2:自己对结果进行排序

findall(Object, Goal, UnsortedWithDuplicates),
sort(UnsortedWithDuplicates, List)

最新更新