/* ***************** The CUT (Chapter 4) ********************* */ /* Example showing how backtrack works */ a :- write('a1 '),b,b. a :- write('a2 '),b. b :- write('b1 '),c. b :- write('b2 '),c. b :- write('b3 '),fail. c :- write('c '). /* Test run: | ?- a. a1 b1 c b1 c true ? ; b2 c true ? ; b3 b2 c b1 c true ? ; b2 c true ? ; b3 b3 a2 b1 c true ? ; b2 c true ? ; b3 no */ /* Example with CUT showing how backtrack works */ aa :- write('a1 '),bb,bb. aa :- write('a2 '),bb. bb :- !,write('b1 '),cc. bb :- write('b2 '),cc. bb :- write('b3 '),fail. cc :- write('c '). /* Test run: | ?- aa. a1 b1 c b1 c true ? ; a2 b1 c yes */ /* Three common uses of CUT. */ /* 1) Confirming the choice of a rule: */ sum_toGood(N,1) :- N=<1,!. sum_toGood(N,R) :- N1 is N-1, sum_toGood(N1,R1), R is R1 + N. sum_toWrong(N,1) :- N=<1. sum_toWrong(N,R) :- N1 is N-1, sum_toWrong(N1,R1), R is R1 + N. /* Better to use \+ than CUT if possible, where \+ is built-in "negation by failure": */ sum_toGood2(N,1) :- N=<1. sum_toGood2(N,R) :- \+(N=<1), N1 is N-1, sum_toGood2(N1,R1), R is R1 + N. /* Testrun: | ?- sum_toGood(2,R). R = 3 yes | ?- sum_toWrong(2,R). R = 3 ? ; R = 4 ? ; R = 4 ? ; R = 3 ? ; R = 1 ? ; R = -2 ? ; R = -6 ? ; R = -11 ? | ?- sum_toGood2(2,R). R = 3 ? ; no */ /* 2) Forced failure, don't try further alternatives (cut-fail): */ income(peter,400000). foreigner(peter). average_taxpayerWrong(X) :- foreigner(X), fail. average_taxpayerWrong(X) :- income(X,I), I < 500000. average_taxpayer(X) :- foreigner(X), !, fail. average_taxpayer(X) :- income(X,I), I < 500000. /* Testrun: | ?- average_taxpayerWrong(peter). yes | ?- average_taxpayer(peter). no */ /* Negation as failure (built-in in gprolog as prefix operator \+) */ not(X) :- call(X), !, fail. not(X). /* 3) Terminating generate-and-test code after first solution found */ /* Divide N1 by N2 */ divide(N1, N2, Result) :- is_integer(Result), div_test(N1, N2, Result), !. /* Generate all integers */ is_integer(1). is_integer(X) :- is_integer(Y), X is Y+1. /* Test for N1/N2 = D */ div_test(N1,N2,D) :- P1 is N2*D, P2 is N2*(D+1), P1 =< N1, P2 > N1. /* CUTs are often problematic if a predicate is later used in other ways than assumed when designing it. Example: */ number_of_parents(adam, 0) :- !. number_of_parents(eve, 0) :- !. number_of_parents(X, 2). /* Test run (first two are OK, last one is wrong): | ?- number_of_parents(eve,X). X = 0 yes {1} | ?- number_of_parents(john,X). X = 2 yes {1} | ?- number_of_parents(eve,2). yes */