我无法想出我需要它的情况。
答案 0 :(得分:19)
优雅系统提供false/0
作为命令式fail/0
的声明性同义词。一个有用的例子是当你手动想要强制回溯副作用时,例如:
?- between(1,3,N), format("line ~w\n", [N]), false.
line 1
line 2
line 3
您可以使用任何失败的目标,例如更短的目标,而不是false/0
:
?- between(1,3,N), format("line ~w\n", [N]), 0=1.
line 1
line 2
line 3
因此,false/0
并非严格需要,但相当不错。
编辑:我有时会看到想要说明“我的关系不适用于空列表”的初学者,然后添加:
my_relation([]) :- false.
到他们的代码。这是不必需,不是使用false/0
的一个很好的例子,例如在以编程方式生成的故障切片中。相反,专注于陈述关于你的关系持有的事情。在这种情况下,只需省略整个子句,并仅为非空列表定义关系,即至少有一个元素:
my_relation([L|Ls]) :- etc.
或者,如果您还要描述除列表之外的其他术语,请使用以下约束:
my_relation(T) :- dif(T, []), etc.
只给出这两个子句中的任何一个(或者两个),查询?- my_relation([]).
将自动失败。没有必要引入一个从未成功的附加条款。
答案 1 :(得分:8)
显式失败。 fail
通常与cut:... !, fail.
一起使用以强制执行失败。
对于所有构造。显式使用fail
/ false
来枚举通过回溯是一项非常容易出错的活动。考虑一个案例:
... ( generator(X), action(X), fail ; true ), ...
因此,我们的想法是为所有X
“做”行动。但是,如果action(X)
失败,会发生什么?这个结构只是继续下一个候选人 - 好像什么也没发生。通过这种方式,某些错误可能会长时间未被发现。
对于此类情况,最好使用失败的\+ ( generator(X), \+ action(X) )
,如果某些action(X)
失败X
。有些系统将其作为内置forall/2
提供。就个人而言,我更喜欢在这种情况下使用\+
,因为\+
更清楚一点,构造不会留下绑定。
故障切片。出于诊断目的,将false
添加到您的程序中通常很有用。有关详细信息,请参阅failure-slice。
答案 2 :(得分:3)
失败的另一个用途是在使用具有副作用的谓词时强制回溯替代方案:
writeall(X) :- member(A,X), write(A), fail.
writeall(_).
有些人可能不会考虑这种特别好的编程风格。 :)
答案 3 :(得分:2)
一个案例(取自Constraint Logic Programming using Eclipse)是not / 1的实现:
:- op(900, fy, not).
not Q :- Q, !, fail.
not _ .
如果Q成功,cut(!)会导致第二个NOT子句被丢弃,并且失败会确保结果为负。如果Q失败,则第二个not子句首先触发。