开发者

What are the uses of the fail predicate in Prolog?

开发者 https://www.devze.com 2023-01-02 23:40 出处:网络
I can\'t come up with a situa开发者_StackOverflow中文版tion where I would need it.Elegant systems provide false/0 as a declarative synonym for the imperative fail/0. An example where it is useful is w

I can't come up with a situa开发者_StackOverflow中文版tion where I would need it.


Elegant systems provide false/0 as a declarative synonym for the imperative fail/0. An example where it is useful is when you manually want to force backtracking for side-effects, like:

?- between(1,3,N), format("line ~w\n", [N]), false.
line 1
line 2
line 3

Instead of false/0, you can also use any goal that fails, for example a bit shorter:

?- between(1,3,N), format("line ~w\n", [N]), 0=1.
line 1
line 2
line 3

Thus, false/0 is not strictly needed but quite nice.

EDIT: I sometimes see beginners who want to state for example "my relation does not hold for the empty list", and then add:

my_relation([]) :- false.

to their code. This is not necessary, and not a good example of using false/0, except for example in failure slices that are programmatically generated. Instead, concentrate on stating the things that hold about your relation. In this case, just leave out the entire clause, and define the relation only for lists that are not empty, i.e., have at least one element:

my_relation([L|Ls]) :- etc.

or, if you are describing other terms in addition to lists as well, use a constraint like:

my_relation(T) :- dif(T, []), etc.

Given only either (or even both) of these two clauses, the query ?- my_relation([]). will automatically fail. It is not necessary to introduce an additional clause which never succeeds for that purpose.


Explicit failure. fail is often used in conjunction with cut: ... !, fail. to enforce failure.

For all construct. Explicit usage of fail/false to enumerate via backtracking is a very error prone activity. Consider a case:

... ( generator(X), action(X), fail ; true ), ...

The idea is thus to "do" action for all X. But what happens, if action(X) fails? This construct simply continues with the next candidate — as if nothing happened. In this manner certain errors may remain undetected for very long.

For such cases it is better to use \+ ( generator(X), \+ action(X) ) which fails, should action(X) fail for some X. Some systems offer this as a built-in forall/2. Personally, I prefer to use \+ in this case because the \+ is a bit clearer that the construct does not leave a binding.

Failure-slice. For diagnostic purposes it is often useful to add on purpose false into your programs. See failure-slice for more details.


One case (taken from Constraint Logic Programming using Eclipse) is an implementation of not/1:

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

If Q succeeds, the cut (!) causes the second not clause to be discarded, and the fail ensures a negative result. If Q fails, then the second not clause fires first.


Another use for fail is to force backtracking through alternatives when using predicates with side effects:

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

Some people might not consider this particularly good programming style though. :)


fail/0 is a special symbol that will immediately fail when prolog encounters it as a goal.

fail is often used in conjunction with CUT(!) to enforce failure.

like(me,X) :- chess(X),!,fail.
like(me,X) :- games(X).
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号