22

我想不出我需要它的情况。

4

5 回答 5

23

优雅的系统提供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([]).将自动失败。没有必要为此目的引入一个永远不会成功的附加条款。

于 2010-06-08T22:54:58.757 回答
10

显式失败。 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到您的程序中通常很有用。有关更多详细信息,请参阅

于 2013-01-29T13:30:12.997 回答
3

一个案例(取自Constraint Logic Programming using Eclipse)是 not/1 的实现:

:- op(900, fy, not).
not Q :- Q, !, fail.
not _ .

如果 Q 成功,则 cut (!) 导致第二个 not 子句被丢弃,而 fail 确保否定结果。如果 Q 失败,则第二个 not 子句首先触发。

于 2010-06-08T22:53:04.300 回答
3

fail 的另一个用途是在使用具有副作用的谓词时强制回溯:

writeall(X) :- member(A,X), write(A), fail.
writeall(_).

不过,有些人可能不会认为这种特别好的编程风格。:)

于 2010-06-09T22:04:25.117 回答
0

fail/0 是一个特殊符号,当 prolog 遇到它作为目标时会立即失败。

fail 通常与 CUT(!) 结合使用以强制失败。

like(me,X) :- chess(X),!,fail.
like(me,X) :- games(X).
于 2021-08-13T11:57:06.127 回答