Sumar
Din breviar:
Pentru a limita recursia pe cazurile de bază, folosim
!/0(predicatul CUT). El este util când avem clauze scrise una sub alta — atunci se face disjuncție între clauze. Dacă se satisface o clauză, Prolog încearcă satisfacerea celorlalte clauze imediat următoare. Pentru a opri acest mecanism, e util CUT.
base_case(params) :- !.
De ce e nevoie
Când avem două clauze pentru același predicat, Prolog încearcă să le satisfacă pe amândouă la backtracking. Fără !, cazul recursiv se poate reaplica peste cazul de bază și produce rezultate greșite sau duplicate.
% FĂRĂ CUT — problematic
min(X, Y, X) :- X =< Y.
min(_, Y, Y).
?- min(2, 5, M).
M = 2 ;
M = 5 . % al doilea răspuns e greșit!
% CU CUT — corect
min(X, Y, X) :- X =< Y, !.
min(_, Y, Y).
?- min(2, 5, M).
M = 2.
Pattern — cazul de bază cu cut
Aproape orice recursie pe liste din breviar arată așa:
sum([], 0) :- !.
sum([H | T], Res) :-
sum(T, ResT),
Res is ResT + H.
Fără ! pe cazul de bază, Prolog ar putea reîncerca să unifice [] cu [H | T] la backtracking (eșuează, dar pierde timp) și poate produce false secundare nedorite.
Pattern — case discrimination
max([], 0) :- !.
max([H | T], MaxTail) :-
max(T, MaxTail),
MaxTail >= H, !.
max([H | T], H) :-
max(T, MaxTail),
H >= MaxTail.
Prima clauză cu ! „blochează” lista vidă. A doua și a treia se discriminează prin comparație; !-ul din a doua previne intrarea în a treia când prima condiție e adevărată.
Când NU folosim cut
Dacă predicatul trebuie să genereze toate soluțiile la backtracking (de ex. member/2, append/3 în mod generator), cut-ul ar tăia soluțiile legitime. Regula de degetar: cut pe clauze de caz de bază și pe discriminări de caz; nu pe predicate care enumeră.