Programmation Logique et Prolog 1
Les flux (1/2)
Prolog gère les entrées/sorties sur des flux (streams)
Un flux peut être en sortie (écriture) ou en entrée (lecture)
Un flux peut être crée vers ou depuis :
un fichier
l'écran
le clavier
une socket
...
Ouvrir un flux : open(+source,+io_mode,-stream)
exemple : ouvrir un fichier 'test.txt' en écriture et récupérer le flux dans une variable S
open('test.txt',write,S).
Programmation Logique et Prolog 2
Les flux (2/2)
Fermer un flux : close(+stream)
Flux sortant courant : current_output(?stream) pour le récupérer, set_output(+stream) pour le modifier
Flux entrant courant : current_input(?stream)pour le récupérer, set_input(+stream) pour le modifier
Prédicats pour manipuler un flux :
seek pour se positionner dans le flux
stream_position pour savoir où on se trouve dans le flux
character_count, line_count pour gérer les flux textes
bufferisation des flux
...
Programmation Logique et Prolog 3
Les sorties (1/2)
Ecriture de termes : write(?term), write(+stream,?term)
write(1+2). écrit à l'écran YES 1+2
write(X). écrit à l'écran, YES _16 (le nom interne de la variable)
open('test.txt',write,S).write(S,coucou). écrit coucou dans le fichier test.txt
Ecriture de termes (suite) : display/1 (ou display/2) agit comme write/1 (ou write/2) mais écrit la représentation sous forme d’arbre
display(S,1+2) écrit sur le flux S YES +(3,4)
Les sorties (2/2)
Mise en page :
nl/0 permet de passer à la ligne
tab/1 affiche N espaces où N est l'entier passé en paramètres
Prédicats d'écriture de caractères : put/1 et put_char/1
put/1 s’utilise en donnant le code ASCII d’un caractère
• put(97). affiche YES a
put_char(97). affiche error.
put_char(e). affiche YES e
Prolog connaît aussi les chaînes de caractères. Elles sont
notées entre « ». Mais pour Prolog la chaîne est la liste de
codes ASCII des caractères la composant .
Programmation Logique et Prolog 5
Les entrées
Lecture de termes : read(?term), read(+stream,?term)
read(R). lit au clavier et met la valeur dans R
La valeur tapée doit être suivie d'un point
open('test.txt',read,S).read(S,F). met dans F le contenu du fichier test.txt. La fin du fichier doit être indiquée par un point (EOF).
Lecture de caractères : get(?term), get(+stream,?term)
Tous les deux prennent en argument un terme unifié avec le code ASCII du caractère lu.
Si l’argument est une variable, celle-ci prendra pour valeur le code ASCII du caractère lu. get ne lit que les caractères de code compris entre 33 et 126.
Programmation Logique et Prolog 6
Exceptions (1/2)
Prolog gère les exceptions à l'aide des prédicats throw(+non_var) et catch(?callable_term,?term,?term)
throw(E) lance une exception :
provoque l'arrêt de la résolution courante
provoque la recherche d'un catch encapsulant la résolution courante
catch(Goal,Catcher,Recovery) :
provoque la résolution de Goal par appel de call(Goal)
si la résolution de Goal ne provoque aucun throw, le résultat du catch est celui du Goal
si Goal lance une exception avec throw(E) :
• si E s'unifie avec Catcher, la résolution du but Recovery est lancée
• sinon Prolog recherche un catch dont la résolution a été lancée précédemment.
Programmation Logique et Prolog 7
Exceptions (2/2)
call(Goal) est un "métaprédicat". Il réussit si le but passé en paramètre réussit. Si le but contient une coupure, elle n'a pas d'influence en dehors du call.
Exemple :
test(0) renvoie YES
test(3) renvoie YES et écrit 'raté'
Le langage
essai(0).
essai(1).
essai(X) :- X>1, throw(excep1).
test(X) :- catch(essai(X),excep1,write('raté')).
Prédicats dynamiques (1/5)
Un programme Prolog est une "base de connaissances"
constituée de faits et de règles
Le mécanisme Prolog permet de mener des raisonnements logiques à partir de cette base pour démontrer ou infirmer un but
On peut aussi gérer dynamiquement la base de connaissances en ajoutant ou en enlevant des faits dans le programme au cours de l'exécution du mécanisme de résolution
=> fonctionnement se rapprochant des "systèmes experts"
Prolog avancé
Programmation Logique et Prolog 9
Prédicats dynamiques (2/5)
Par défaut, un prédicat est statique. Un prédicat qu'on veut pouvoir manipuler dynamiquement doit être déclaré comme tel avec la directive dynamic/1 en précisant l'arité du prédicat
Ajout de faits et de règles :
asserta/1 insère la clause en tête du programme
assertz/1 insère la clause en queue de programme
Retrait de faits et de règles :
retract/1 retire le premier fait rencontré qui s'unifie avec le prédicat
retractall/1 retire toutes les clauses dont la tête s'unifie avec le prédicat
abolish/1 permet de retirer une règle du programme
:- dynamic(homme/1).
:- dynamic(parent/2).
Programmation Logique et Prolog 10
Prédicats dynamiques (3/5)
:- dynamic(homme/1).
:- dynamic(femme/1).
:- dynamic(parent/2).
:- dynamic(enfant/2).
homme('Roger').
femme('Rose').
parent('Roger','Rose').
ajout :- asserta(homme('Robert')),asserta(parent('Roger','Robert')).
retrait :- retract(parent(_,_)).
ajoutRegle :- C = (enfant(X,Y) :- parent(Y,X)), assertz(C).
suppRegle :- abolish(enfant/2).
Exemple_Prolog
Programmation Logique et Prolog 11
Prédicats dynamiques (4/5)
Pour savoir si une clause est dans le programme :
clause(+head, ?body) réussit s'il existe dans le programme une clause qui s'unifie avec head :- body.
clause ne marche que pour les clauses publiques : par défaut une clause est privée et une clause dynamique est publique ; on peut déclarer une clause publique avec la directive public/1
Exemples :
clause(humain(R),B). renvoie YES {B=homme(R)} ou {B=femme(R)}
clause(concat(X,Y,Z),B). renvoie YES {B=true,X=[],Z=Y} ou {B=concat(A,Y,C),X=[D|A],Z=[D|C]}
:- public(humain/1).
humain(X) :- homme(X).
humain(X) :- femme(X).
:- public(concat/3).
concat([],X,X).
concat([X|Xs], Ys, [X|Zs]) :- concat(Xs,Ys,Zs).
Prédicats dynamiques (5/5)
Intérêts des prédicats dynamiques :
résistance au backtrack : un ajout ou retrait dynamique n'est pas annulé par un retour en arrière dans l'arbre de recherche
améliore l'efficacité des programmes : les faits intermédiaires déjà calculés lors d'une résolution antérieure peuvent être sauvegardés
Inconvénients des prédicats dynamiques :
coût de la mise en mémoire des prédicats
place occupée en mémoire par les prédicats
Programmation Logique et Prolog 13
Méta-programmation
Programmation "normale" : les programmes opèrent sur des donnés
Méta-programmation : les programmes opèrent sur des programmes
les programmes analysent, transforment ou simulent d’autres programmes
Prolog est un langage adapté à la méta-programmation car il y a identité formelle entre programme et données (règles et faits)
Le langage
Programmation Logique et Prolog 14
Méta-interprète
Le langageprouve(true).
prouve((A,B)) :- prouve(A), prouve(B).
prouve(But) :- clause(But,Corps), prouve(Corps).
Un méta-interprète d’un langage donné est un interprète du langage écrit dans le même langage
Le plus simple des méta-interprètes Prolog :
Un méta-interprète un peu plus intéressant :
prouve(But) :- But.
Programmation Logique et Prolog 15
Améliorations
Gestion des prédicats prédéfinis :
Gestion explicite de l’unification :
Le langage
predefini(_ = _).
predefini(_ is _).
...
prouve(But) :- predefini(But), But.
prouve(But) :- But =.. [Foncteur|Arguments], Tete =.. [Foncteur|AutresArguments], clause(Tete, Corps),
unification(But, Tete), prouve(Corps).
Algorithme d’unification
Le langageunification(X, Y) :- var(X), !, Y = X.
unification(X, Y) :- var(Y), !, X = Y.
unification(X, Y) :- atomic(X), atomic(Y), X == Y.
unification(X, Y) :- X =.. [Foncteur|Arguments],
Y =.. [Foncteur|AutresArguments],
unificationListe(Arguments, AutresArguments).
unificationListe([], []).
unificationListe([X|Xs], [Y|Ys]) :- unification(X,Y),
unficationListe(Xs,Ys).
Rappels :
var(?term) réussit si le terme est une variable non instanciée
atomic(?term) réussit si le terme est instancié par un atom (identificateur ou nombre)
Programmation Logique et Prolog 17
Le test d’occurrence
Théoriquement, lors d’une unification il faut réaliser le test d’occurrence. Prolog ne le fait pas.
Exemple : ?
- X = f(X).réussit mais ne peut afficher de résultat !
Test d'occurrence d'une variable dans un terme :
Le langage
noccur(_, Y) :- atomic(Y).
noccur(X, Y) :- var(Y), X \== Y.
noccur( X, Y) :- Y =.. [_|Arguments], nooccurListe(X, Arguments).
nooccurListe(_, []).
nooccurListe(X, [Y|Ys]) :- nooccur(X,Y), nooccurListe(X,Ys).
Programmation Logique et Prolog 18
Traitement des langues (1/4)
Prolog a été développé à l'origine autour de la problématique du traitement automatique des langues naturelles
On veut pouvoir analyser des phrases :
déterminer si une phrase donnée est syntaxiquement correcte
générer des phrases syntaxiquement correctes
On se donne des règles de grammaire
Exemple de grammaire :
Phrase ::= GroupeNominal VerbeTransitif Complement |GroupeNominal VerbeIntransitif
GroupeNominal ::= NomPropre | Article NomCommun
Complement ::= GroupeNominal
Programmation Logique et Prolog 19
Traitement des langues (2/4)
Prédicat de concaténation de "mots" :
Prédicats exprimant les règles de la grammaire :
append_words(A,B,R) :- atom_chars(A,AList),atom_chars(B,BList), append(AList,[' '],X),append(X,BList,RList), atom_chars(R,RList).
grnom(X) :- art(A),nc(N),append_words(A,N,X).
grnom(X) :- np(X).
complement(X) :- grnom(X).
phrase(X) :-
grnom(A),vt(V),complement(C),append_words(A,V,T),append_words(T,C,X).
phrase(X) :- grnom(A),vi(V),append_words(A,V,X).
Traitement des langues (3/4)
Le dictionnaire :
Le but phrase('titi mange le chat'). renvoie YES
Le but phrase('un titi mange le chat') renvoie NO
Le but phrase(P). renvoie YES {P='un canari deteste un canari'} ou {P='un canari deteste un chat'} ou ...
np('Titi').
np('Grosminet').
nc(canari).
nc(chat).
art(un).
art(le).
vt(deteste).
vt(mange).
vi(vole).
vi(dort).
Exemple_Prolog
Programmation Logique et Prolog 21
Traitement des langues (4/4)
On peut ajouter des règles pour contrôler le genre, le nombre, les différents types de compléments, ...
On peut ajouter des règles pour contrôler la sémantique du langage :
Titi ne peut pas manger Grosminet!