2

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

false
  • 10,264
  • 13
  • 101
  • 209
Apex Predator
  • 171
  • 1
  • 3
  • 13
  • 2
    Yes. `fail` means *fail*. :) That means it will backtrack. But `!` means *cut* and means it will not backtrack further back from that point in the clause. If your example is a single clause predicate, then it doesn't do anything since there's nothing to backtrack to anyway. But if you had another `p(X,Y) :- s(X, Y).` *after* the one you show, then it would not ever be exercised due to the cut in the prior clause (since the prior clause only has variables for arguments and will always match a `p(X, Y)` query before the second clause does). – lurker Feb 24 '15 at 13:29
  • 2
    You should get good Prolog book (such as *Programming in Prolog* by Clocksin and Mellish for introductory material, or *The Art of Prolog* by Sterling and Shapiro) because they explain these concepts quite thoroughly. :) – lurker Feb 24 '15 at 13:32
  • Ok thanks a lot, i had actually downloaded that but didn't have a chance to read it lol, but will definitely read it! – Apex Predator Feb 24 '15 at 21:32

1 Answers1

4

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.