Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are the uses of the fail predicate in Prolog?

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

like image 828
Igor Avatar asked Jun 08 '10 22:06

Igor


People also ask

What are the predicates in Prolog?

A Prolog program consists of predicate definitions. A predicate denotes a property or relationship between objects. Definitions consist of clauses. A clause has a head and a body (Rule) or just a head (Fact).

Is failure is possible in backtracking?

While backtracking or 'standard' evaluation left-to-right, the fail predicate always fails, as the name implies. We can take advantage of this by combining it with Prolog's automatic backtracking to find all the clauses in the database with a specified property.

How do you negate a predicate in Prolog?

To cut or not to cut - Negation The negation predicate in prolog is \+ and therefore \+ round(earth) returns true. This limitation of prolog that is a goal cannot be proved then it is false, is called the close world assumption (CWA).

How do you use not in Prolog?

Because of the problems of negation-as-failure, negation in Prolog is represented in modern Prolog interpreters using the symbol \+ , which is supposed to be a mnemonic for not provable with the \ standing for not and the + for provable.


4 Answers

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.

like image 59
mat Avatar answered Oct 01 '22 04:10

mat


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.

like image 27
false Avatar answered Oct 01 '22 05:10

false


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.

like image 35
G__ Avatar answered Oct 01 '22 05:10

G__


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

like image 42
hdan Avatar answered Oct 01 '22 05:10

hdan