95.307 - Programming Paradigms | 1999 |
11 Cut |
11.1 How to Stop Prolog from Succeeding? |
member(X, [X|_]).
member(X, [_|Y]) :- member(X,Y).?- member(a, [a, b, c, a, b, c, a]).
succeeds 3 times
CUT commits the system to every choice it has made since it chose the rule.
client('bob').
client('dwight').book_overdue('bob', book100).
book_overdue('dwight', book101).general_facility(X) :- basic_facility(X).
general_facility(X) :- additional_facility(X).additional_facility(borrowing).
additional_facility(inter_library_loan).basic_facility(references).
basic_facility(enquires).facility(Person, Facility) :-
book_overdue(Person, Book),
!, <------------------------------- If a person has any overdue book, he has access to only basic facility
basic_facility(Facility).
facility(Person, Facility) :- general_facility(Facility).
?- client(X), facility(X,Y).
If a client is found to have an overdue book, then
only allow the client the basic facilities of the library. Don't bother
going through all the clients overdue books and don't consider any other
rule about facilities.
11.2 Common Uses of Cut |
sum_one_to(X,Y). The sum of numbers from 1 to X is Y?- sum_one_to(5,Y).
Y = 15;
NOsum_one_to(1,1) :- !.
sum_one_to(N, Result) :-
N1 is N - 1,
sum_one_to(N1, Result1),
Result is Result1 + N.
sum_one_to(N,1) :- N =< 1, !.
sum_one_to(N, Result) :-
N1 is N - 1,
sum_one_to(N1, Result1),
Result is Result1 + N.
Format: not(goal).
Semantics: not succeeds if the goal does not
sum_one_to(1,1).
sum_one_to(N, Result) :-
not (N = 1),
N1 is N - 1,
sum_one_to(N1, Result1),
Result is Result1 + N.Better Non Cut Version
sum_one_to(N,1) :- N =< 1.
sum_one_to(N, Result) :-
not (N = <1),
N1 is N - 1,
sum_one_to(N1, Result1),
Result is Result1 + N.
A :- B, C.
A :- not(B), D.
A :- B, !, C.
A :- D.
1) average_taxpayer(X) :- foreigner(X), fail.
2) average_taxpayer(X) :- ....
average_taxpayer(X) :- foreigner(X), !, fail.
average_taxpayer(X) :-
spouse(X,Y),
gross_income(Y, Income),
Income < 5000.
average_taxpayer(X) :-
not (foreigner(X)),
spouse(X,Y),
gross_income(Y,
Income)
Income <
5000.
gross_income(X,Y) :-
receives_pension(X, P),
P < 5000,
!,
fail.
not(P) :- call(P), !, fail.
not(P).
aline([1,2,3]).
aline([4,5,6]).
aline([7,8,9]).
aline([1,4,7]).
aline([2,5,8]).
aline([3,6,9]).
aline([3,5,7]).
aline([1,5,9]).//Is there a forced move (a square) on the board (list of elements)
forced_move(Board, Sq) :-
aline(Squares), <- ----- Generate
threatening(Squares, Board, Sq), <- ------Test
!. <--------Fail, no need to look further, found answer, must make move
threatening([X,Y,Z], B, X) :-
empty(X,B),
cross(Y,B),
cross(Z,B).threatening([X,Y,Z], B, Y) :-
empty(Y,B),
cross(X,B),
cross(Z,B).threatening([X,Y,Z], B, Z) :-
empty(Z,B),
cross(X,B),
cross(Y,B).empty(Square, Board) :-
arg(Square, Board, Value),
var(Value).cross(Square, Board) :-
arg(Square, Board, Value),
nonvar(Value),
Value = x.nought(Square, Board) :-
arg(Square, Board, Value),
nonvar(Value),
Value = 0.
Note:
?- arg(2, related(john, mother(jane)), X).
X = mother(jane).?- arg(2, [a, b, c], X)
X = [b,c].var(X) succeeds if X has no binding
novar(X) succeeds if X has a valuenovar(X) :- var(X), !, fail.
novar(_).
11.3 Cut Problems |
append([],X,X) :- !.
append([A|B], C, [A|D]) :- append (B,C,D).?- append([a,b,c], [d,e], X). works ok
?- append([a,b,c], X, Y). works okBut
?- append(X, Y, [a,b,c]).
produces the solution X = [], Y = [a,b,c]. but because of the cut we can get no more solutions, even though they exist.
What happens with the following:
number_of_parents(adam, 0) :- !.So
number_of_parents(eve, 0) :- !.
number_of_parents(X, 2).
?- number_of_parents(eve, X). gives X = 0
?- number_of_parents(john, X). gives X = 2
?- number_of_parents(eve, 2). gives YESBetter solution number_of_parents(adam, N) :- !, N = 0.
number_of_parents(eve, N) :- !. N = 0.
number_of_parents(X, 2).
However,
?- number_of_parents(X,Y). give only one solution with X = adam, N = 0.
If you introduce cuts to obtain correct behavior when the goals are of one form (e.g., a special sequence of variables), there is no guarantee that anything sensible will happen if goals of another form start appearing.
11.4 Other Colors of Cuts |
minimum(X,Y,Z) -> the minimum of X and Y is Z.minimum(X,Y,X) :- X < Y, !.
minimum(X,Y,Y) :- X > Y, !.
minimum(X,Y,Z) -> the minimum of X and Y is Z.minimum(X,Y,X) :- X < Y, !.
minimum(X,Y,Y) . The explicit conditions governing the use of the rule are omitted.
Problem ?- minimum(2,5,5) succeedsA standard Prolog programming technique using red cuts is the omission of explicit conditions. Knowledge of the behavior of Prolog, the order it uses rules in a program, is relied on to omit conditions that could be inferred to be true. This is sometimes essential in practical Prolog programming, since explicit conditions, especially negative ones, are cumbersome to specify, and inefficient to run. But making such omissions is error prone.