Apex Predator
Apex Predator

Reputation: 171

Cutting the beginning of a clause and the relation between "cut", `!`, and `fail`

What does it mean to put the cut (!) at the very beginning of a clause?

  p(X,Y) :- !, q(X), r(X,Y).

What is the difference between ! and fail and how are they related?

thanks.
I'm thinking that for fail, the predicate will just "fail" lol which is different from not backtracking? just want to be sure :)

Upvotes: 2

Views: 594

Answers (1)

user1812457
user1812457

Reputation:

Usually, you use this when you want to make sure that there is no backtracking on a certain combination of variable instantiations. To show some code (borrowed a bit from the SWI-Prolog implementation:

read_lines(In, Ls) :-
    read_line_to_codes(In, Codes),
    read_lines_rest(Codes, In, Ls).

read_lines_rest(end_of_file, _, []) :- !.
read_lines_rest(Codes, In, [Codes|Rest]) :-
    read_line_to_codes(In, New_codes),
    read_lines_rest(New_codes, In, Rest).

Now, with these predicates defined, you can read an input stream (a file, for example) to a list of lines. We are using read_line_to_codes/2 from library(readutil). It will unify its second argument with a list of codes representing a line, or the atom end_of_file at the end of input.

In the first clause of read_lines_read/3, we use unification in the head of the predicate definition. We "demand" that the first argument must be the atom end_of_file if we want the predicate to be even considered. When (at the end of input) this clause succeeds, the other possible solution in the second clause of the definition is not taken in consideration, and the predicate succeeds, closing up the list in the third argument.

Here it is used:

?- open('shortcut.pl', read, In), read_lines(In, Ls), forall(member(L,Ls), format("~s~n", [L])).
read_lines(In, Ls) :-
    read_line_to_codes(In, Codes),
    read_lines_rest(Codes, In, Ls).

read_lines_rest(end_of_file, _, []) :- !.
read_lines_rest(Codes, In, [Codes|Rest]) :-
    read_line_to_codes(In, New_codes),
    read_lines_rest(New_codes, In, Rest).
% variable instantiations

You should notice that the predicate succeeds exactly once. Try removing the cut in the first clause to see what happens.

As for the fail, yes, it makes the predicate fail (not succeed). At this point, if there are any choice points left, Prolog will backtrack to the most recent one.

Upvotes: 4

Related Questions