我想不出我需要它的情况。
5 回答
优雅的系统提供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([]).
将自动失败。没有必要为此目的引入一个永远不会成功的附加条款。
显式失败。 fail
常与 cut 连用:... !, fail.
强制失败。
对于所有构造。通过回溯显式使用fail
/false
进行枚举是一个非常容易出错的活动。考虑一个案例:
... ( generator(X), action(X), fail ; true ), ...
因此,这个想法是为所有人“做”行动X
。但是如果action(X)
失败了会发生什么?这个结构只是继续下一个候选人——就好像什么都没发生一样。以这种方式,某些错误可能会保持很长时间未被检测到。
对于这种情况,最好使用\+ ( generator(X), \+ action(X) )
which failed, should action(X)
fail for some X
。一些系统将其作为内置的forall/2
. 就个人而言,我更喜欢\+
在这种情况下使用,因为\+
结构不会留下绑定更清楚一点。
失败切片。出于诊断目的,故意添加false
到您的程序中通常很有用。有关更多详细信息,请参阅故障切片。
一个案例(取自Constraint Logic Programming using Eclipse)是 not/1 的实现:
:- op(900, fy, not).
not Q :- Q, !, fail.
not _ .
如果 Q 成功,则 cut (!) 导致第二个 not 子句被丢弃,而 fail 确保否定结果。如果 Q 失败,则第二个 not 子句首先触发。
fail 的另一个用途是在使用具有副作用的谓词时强制回溯:
writeall(X) :- member(A,X), write(A), fail.
writeall(_).
不过,有些人可能不会认为这种特别好的编程风格。:)
fail/0 是一个特殊符号,当 prolog 遇到它作为目标时会立即失败。
fail 通常与 CUT(!) 结合使用以强制失败。
like(me,X) :- chess(X),!,fail.
like(me,X) :- games(X).