Search code examples
prologswi-prolog

Prolog cut and fail not working as expected


I'm learning prolog and I've come across the "cut and fail" combination, and from my understanding they could be used as guard clauses. I've tried experimenting with it but it doesn't work as expected.

old(person1).
old(person2).
skilled(person1).
skilled(person2).
skilled(person3).
skilled(person4).
possible_employee(X):-
    old(X),!,fail.
possible_employee(X):-
    skilled(X).

In the example above, it should "filter out" old people, but it filters out everyone and returns false when querying for a possible_employee. Is my code flawed or my understanding of the concept?


Solution

  • (old(X) ; skilled(X)), possible_employee(X) will do what you want.

    member(X, [person1, person2, person3, person4]), possible_employee(X) will do what you want.

    Your predicate filters out solutions. It can't be used in generative fashion, because of the cut. As soon as old(X) is fulfilled, the predicate possible_employee/1 irrevocably fails, as prescribed. So it must be supplied with some more possibilities, from some outside source. It itself is done at that point.

    What your predicate is (re-)implementing, is "not", \+.

    In Prolog, not is not "not". It must be read as "can not prove that ...".

    Under this reading, the meaning of possible_employee(X) is, "can't prove old(X), and can prove skilled(X)". But old(X) with the fresh X can always be proved, with that knowledge base.

    If the clauses order is switched, it completely changes the predicate's meaning. A predicate's (several) clauses are in an implied disjunction, "or":

    possible_employee(X):-
        skilled(X).
    possible_employee(X):-
        old(X),!,fail.
    

    means, "can prove skilled(X)", and nothing else (do you see why?). So then, under

    old(person1).
    old(person2).
    skilled(person1).
    skilled(person2).
    skilled(person3).
    skilled(person4).
    possible_employee(X):-
        skilled(X).
    possible_employee(X):-
        old(X),!,fail.
    

    the call possible_employee(X) should succeed four times, for all the four persons. And it does, even though the two of them are also old/1.

    So you see, the presence of cut changes everything. It makes the predicate's meaning totally dependent on operational semantics.

    In logic, A ; B is the same as B ; A. But not operationally so.

    Bring the cut in, forget the logic, start thinking of operation details of Prolog interpretation.