Cette note de cours a été réalisée d'après le cours de l'ISMRA de Caen, où j'ai repris la partie des notes de cours consacrée à la négation et au Cut. On peut aussi se reporter au diaporama téléchargeable de l'université de Montréal.
L'exécution d'un "programme" Prolog passe toujours par des retours en arrière. On note, par convention, l'exécution de P(X) par:
Le predicat prédéfini " ! " - le cut - permet d'empêcher le retour en arrière.
Ainsi, alors que la règle p(X) :- a(X), b(X). a la boîte d'exécution:
La règle p(X) :- a(X), !, b(X). a la boîte d'exécution suivante :
Une fois un cut franchi :
Les conséquences du cut sont d'améliorer l'efficacité et d'exprimer le déterminisme; mais il revient à faire fonctionner le Prolog comme un langage procédural et il peux introduire des erreurs de programmation vicieuses. Il faut donc l'utiliser avec parcimonie.
La fusion de 2 listes triées est déterministe :
On peut donc éliminer les possibilités de retour en arrière :
fusion([], L, L).Bonne utilisation : cuts verts (ne modifie pas le sens d'un programme). Par exemple, la fusion.
Mauvaise utilisation : cuts rouges (paresseux), par exemple, le minimum
min(X, Y, X) :- X < Y, !.Ce prédicat conduit bien au calcul du minimum pour la première solution. Le cut est nécessaire pour éviter de produire une seconde solution au cours d'un retour en arrière. Si on a la règle :
P :- B1 , ..., Bi, min(2, 3, Z), Bj, ..., Bn .À la première exécution, Z = 2 . Si on revient en arrière à cause d'un échec des buts Bj,..., Bn et si min/3 ne comporte pas de cut, on obtient Z = 3 car min/3 aurait pu produire deux solutions. On repartirait alors avec cette valeur pour prouver buts Bj,..., Bn.
Autre cut rouge:
ifthenelse(P, Q, R):- P, !, Q.Le symbole de la négation: "\+" (anciennement not )
Un programme logique exprime ce qui est vrai. La négation, c'est donc ce que l'on ne peut pas prouver :
Le prédicat not peut être défini par :
not(P) :- P, !, fail.Avec un not, il vaut mieux que les variables soient instanciées :
?- \+ member(X, [a, b]).Le programme identifie X à une des variables, réussit et le not le fait échouer.
De même dans une règle, il faut veiller à l'instanciation des variables. Avec le programme :
marie(francois).La requête suivante échoue :
?-etudiant_celibataire(X).car X s'apparie à françois puis le not fait échouer. Alors que :
?- etudiant_celibataire(rene).réussit car X = rene donc \+ marie(rene) est vrai.
Pour que la règle produise les résultats attendus, il faut inverser les sous buts :
étudiant_célibataire(X) :- etudiant(X), \+ mari(X).Ainsi X sera instancié avant d'être soumis au \+ .