What are the uses of the fail predicate in Prolog?
Asked Answered
C

5

23

I can't come up with a situation where I would need it.

Camorra answered 8/6, 2010 at 22:35 Comment(0)
S
23

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.

Smiga answered 8/6, 2010 at 22:54 Comment(1)
s/elegant/elegant and conforming/Mcwhorter
M
10

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 for more details.

Mcwhorter answered 29/1, 2013 at 13:30 Comment(0)
O
3

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.

Oblast answered 8/6, 2010 at 22:53 Comment(0)
A
3

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. :)

Adam answered 9/6, 2010 at 22:4 Comment(1)
Oops, looks like mat beat me to it.Adam
R
0

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).
Regularly answered 13/8, 2021 at 11:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.