Le contrôle de l’effacement des buts
Le contrôle
A chaque étape la machine Prolog doit faire deux choix :
L’un pour choisir un but dans une suite de buts à effacer. C’est le premier élément de la suite qui est toujours choisi. C’est à dire que pour effacer une suite de buts q0 q1 … qn, on efface d’abord q0 et ensuite q1 … qn.
L’autre pour choisir la règle qui sert à effacer un but b. C’est la première règle dont la tête s’unifie avec le but b qui est choisie.
Cela peut se résumer par le programme Prolog suivant :
effacer(nil) -> ;
effacer(t.l) -> rule(t, q) effacer(q) effacer(l) ;
rule(t,q) est une règle prédéfinie (voir le chapitre 3) qui donne par énumération toutes les règles dont la tête s’unifie avec t et la queue avec q.
Le moyen de contrôle consiste à modifier ou à restreindre les deux choix précédents. La manière dont Prolog fait ces choix peut amener certains programmes boucler et par conséquent à ne pas se comporter comme on pouvait l’espérer. Les deux exemples suivants illustrent ce phénomène.
Exemple 1 : Un cas typique est celui de la transitivité. Quand on cherche à effacer plus_grand(Jo,x) en utilisant le programme suivant, on retrouve une instance de ce même but à effacer. Le programme se met alors à boucler et se termine par un débordement1 de pile (ou par une interruption utilisateur!). La manière correcte d’écrire ce programme consiste à enlever la récursivité à gauche.
plus_grand(Jo, Max) -> ;
plus_grand(Max, Fred) -> ;
plus_grand(x, y) -> plus_grand(x, z) plus_grand(z, y);
1Si le système de réallocation automatique n’est pas désactivé au démarrage de Prolog, un certain nombre de réallocations se produiront avant le débordement.
plus_grand(Jo, x); {x=Max}
{x=Fred}
DEBORDEMENT
« Une bonne solution »
plus_grand'(Jo, Max) -> ;
plus_grand'(Max, Fred) -> ;
plus_grand(x, z) -> plus_grand'(x, y) plus_grand_ou_egal(y, z);
plus_grand_ou_egal(x, x) ->;
plus_grand_ou_egal(x, y) -> plus_grand(x, y);
Exemple 2 : Cet exemple énumère toutes les listes construites avec 1. Avec le (mauvais) programme ci- dessous, c’est d’abord la liste infinie qui devrait être produite; bien entendu, la bonne solution s’obtient en permutant l’ordre des deux règles.
Aociation Prolog
HERITAGE
liste_de_un(1.x) -> liste_de_un(x) ;
liste_de_un(nil) -> ;
>liste_de_un(x);
DEBORDEMENT1
La coupure “!”
Normalement Prolog essaye d’effacer une suite de buts de toutes les manières possibles. Mais si on utilise une règle contenant un «!» (ou coupure ) pour effacer un but q, l’effacement de ce «!» supprimera tous les choix de règles restant à faire pour effacer ce but q. Cela restreint la taille de l’espace de recherche : on peut dire que «!» fait «oublier» les autres manières possibles d’effacer q.
Le «!» ne peut apparaître que parmi les termes qui constituent le membre droit d’une règle. Les choix qui restent à examiner et que l’effacement du «!» fait «oublier» sont :
les autres règles ayant la même tête que celle où le «!» figure les autres règles qui auraient pu être utilisées pour effacer les termes compris entre le début de la queue et le «!»
Cette question est illustrée par les exemples suivants :
couleur(rouge) ->;
couleur(bleu) ->;
taille(grand) ->;
taille(petit) ->;
choix1(x.y) -> couleur(x) taille(y);
Le contrôle de l’effacement des buts R2-3
choix1(« c’est tout ») ->;
choix2(x.y) -> ! couleur(x) taille(y); choix2(« c’est tout ») ->;
choix3(x.y) -> couleur(x) ! taille(y); choix3(« c’est tout ») ->;
choix4(x.y) -> couleur(x) taille(y) !; choix4(« c’est tout ») ->;
>choix1(u);
{u=rouge.grand}
{u=rouge.petit}
{u=bleu.grand}
{u=bleu.petit}
{u= »c’est tout »}
>choix2(u);
{u=rouge.grand}
{u=rouge.petit}
{u=bleu.grand}
{u=bleu.petit}
>choix3(u);
{u=rouge.grand}
{u=rouge.petit}
>choix4(u);
{u=rouge.grand}
>choix1(u) !;
{u=rouge.grand}
On peut considérer le «!» comme une annotation que l’on fait à un programme pour le rendre plus efficace; bien entendu, cela ne se justifie que si on ne s’intéresse qu’à la première solution fournie par ce programme.
Des utilisations classiques du «!» sont :
» Première solution uniquement »
premiere_solution_uniquement(b) -> b !;
» Si Alors Sinon »
si_alors_sinon(p,a,b) -> p ! a;
si_alors_sinon(p,a,b) -> b;
» non »
non(p) -> p ! fail;
non(p) -> ;
Dans le cas de non montré ci-dessus, il faut remarquer que l’on peut avoir des résultats inattendus si p contient des variables libres. C’est ce que montre le petit exemple suivant :
homme(Abélard) -> ;
femme(x) -> non(homme(x));
>femme(Eloïse);
{}
>femme(Abélard);
>femme(x) eq(x, Eloïse);
>
^(X,Y)
X doit être une variable et Y un terme quelconque.
^(X, Y) signifie: il existe X tel que Y soit vrai, et est équivalent à un appel de Y. L’utilisation de ce prédicat (qui est aussi un opérateur) n’a de sens que dans les prédicats bagof/3 et setof/3 , pour indiquer les variables existentielles et les retirer de l’ensemble des variables libres.
bagof(x, p, l)
Pour chaque instantiation différente de l’ensemble des variables libres du but p, non existentielles et n’apparaissant pas dans le terme x, unifie l avec la liste de toutes les solutions x lorsqu’on efface p. Chaque liste l est construite suivant l’ordre des solutions trouvées. Exemple:
aa(2,1) -> ;
aa(1,2) -> ;
aa(1,1) -> ;
aa(2,2) -> ;
aa(2,1) -> ;
>bagof(X, aa(X,Y),L);
{Y=1, L= 2.1.2.nil}
{Y=2, L= 1.2.nil}
bagof(X,Y^aa(X,Y),L);
{L=2.1.1.2.2.nil}
block(e, b), block_exit(e)
block est une règle prédéfinie qui permet de terminer brutalement l’effacement d’un but b. Cette primitive est faite essentiellement pour la récupération des erreurs. On peut considérer que :
Pour effacer block(e, b) on efface b en ayant auparavant créé une paire de parenthèses fictives, étiquetées par e, autour du but b.
block_exit(e) provoque l’abandon immédiat de l’effacement de tous les buts inclus entre les parenthèses étiquetées par e et supprime tous les choix éventuels en attente pour ces buts. L’effacement continue ensuite normalement, après les parenthèses étiquetées par e.
De plus :
Une étiquette est un terme Prolog quelconque, et on considère que deux parenthèses étiquetées sont identiques si leurs étiquettes respectives sont unifiables.
S’il y a plusieurs parenthèses étiquetées par e, block_exit(e) s’arrête au couple de parenthèses le plus interne.
Si block_exit(e) ne rencontre pas de parenthèses e, alors on revient au niveau de commande avec le message d’erreur correspondant à e, si e est un entier, ou le message ‘block_exit’ SANS ‘block’ CORRESPONDANT, si e n’est pas un entier.
Le contrôle de l’effacement des buts R2-5
C’est ce même mécanisme qui est utilisé pour la gestion des erreurs dans Prolog. Une erreur rencontrée dans l’exécution de Prolog provoque l’effacement du but block_exit(i) où i est un entier correspondant au numéro de l’erreur. De cette manière l’utilisateur peut récupérer toutes les erreurs de Prolog, pour pouvoir les traiter dans son application.
Lorsque les optimisations de compilation sont actives (option -f o1 au lancement de Prolog), la compilation de block est optimisée et la décompilation d’un tel but ne sera pas identique mais équivalente au but d’origine. Le but block(e,b) apparaissant dans une queue de règles, sera décompilé en block(e’,_,b’).
La règle prédéfinie quit génère un block_exit(14). Elle est définie ainsi :
quit -> block_exit(14);
quit(i) -> block_exit(14,i);
A titre d’illustration voici un programme qui lit une suite de commandes :
executer_commande ->
block(fin_commande, toujours(lire_et_exec));
lire_et_exec -> outm(« ? ») in_char'(k) exec(k);
exec(« q ») -> block_exit(fin_commande) ;
exec(« f ») -> block_exit(16) ; /* Interruption */
exec(« n ») -> ;
toujours(p) -> repeter p fail ;
repeter -> ;
repeter -> repeter ;
Dans cet exemple, la commande « q » utilise block_exit pour retourner au niveau supérieur de executer_commande. La commande « f » simule une erreur Prolog et rend le contrôle au block qui traite les erreurs de Prolog (puisque 16 ne peut s’unifier avec fin_ commande). S’il n’y a pas de block englobant, on revient au niveau supérieur de Prolog.
block(e, c, b), block_exit(e, c)
Fonctionnement analogue aux formes précédentes, avec deux «étiquettes» e et c à la place d’une seule. b est le but à effacer. block(e,c,b) lance l’effacement de b; l’effacement ultérieur de block_exit à deux arguments produira la recherche d’un block dont les deux premiers arguments s’unifient avec les deux arguments de block_exit.
Lorsque les optimisations de compilation sont actives (option – f o1 au lancement de Prolog), la compilation de block est optimisée et dans certains cas la décompilation d’un tel but ne sera pas identique mais équivalente au but d’origine. Le but block(e,c,b) apparaissant dans une queue de règles, sera décompilé en block(e’,c’,b’).
Ensemble, ces deux règles prédéfinies constituent une sorte de raffinement du mécanisme de récupération des erreurs; en pratique, e correspond au type d’erreur guetté; c correspond à un «complément d’information» rendu par le mécanisme de détection.
Un grand nombre de règles prédéfinies utilisent cette deuxième étiquette comme complément d’erreur. C’est souvent l’argument, cause de l’erreur, qui y est transmis. En phase de mise au point de programmes, cela peut paraître encore insuffisant. Dans le kit, des modules objets : dbgbase.mo, dbggraph.mo et dbgedin.mo, sont fournis. Ils permettent, après rechargement, en cas d’erreur, d’avoir des messages encore plus complets. Le deuxième argument de block sera unifié avec un terme de la forme :
prédicat d’appel ou < prédicat d’appel, complément d’erreur>
Lorsque block_exit(e,c) est effacé dans un environnement «parenthésé» par block(e’,b), alors block_exit(e,c) se comporte comme block_exit(e). Inversement, lorsque block_exit(e) est effacé dans un environnement «parenthésé» par block(e’,c’,b) alors block_exit(e) se comporte comme block_exit(e,nil)
Erreurs et sous-sessions Prolog
Tout ce qui est dit ci-dessus concernant le mécanisme d’erreur block / block_exit, est vrai à l’intérieur d’une même session Prolog. Lorsqu’il s’agit de transmettre une erreur à travers une ou plusieurs sous-sessions (par exemple lorsqu’un but est lancé par menu), deux restrictions sont à mentionner :
– le deuxième argument de block _exit (souvent utilisé comme complé-ment d’erreur) n’est pas transmis. Il vaudra toujours nil.
le premier argument de block_exit est transmis uniquement s’il est de type entier. Dans le cas contraire c’est l’entier 317, pour l’erreur : ‘block_exit’ SANS ‘block’ CORRESPONDANT, qui est propagé.
Interruption
A tout instant un programme Prolog peut être interrompu au moyen d’une touche déterminée, dépendant du système utilisé (par exemple : <Ctrl-C>). Cette interruption est prise en compte par le mécanisme général des erreurs de Prolog et correspond à l’erreur 16. Cette erreur peut donc être récupérée par l’utilisateur. Sinon on revient au niveau de commande avec le message d’erreur suivant : INTERRUPTION UTILISATEUR.
bound(x)
bound(x) s’efface si x est lié. Une variable est considérée comme liée si elle a été unifiée contre :
une constante (entier, réel, identificateur, chaîne),
un terme de la forme t1.t2,
un terme de la forme <t1, t2, … , tn> ou ff(t1, t2, … , tn).
Le contrôle de l’effacement des buts R2-7 dif(t1, t2)
La règle prédéfinie dif(t1, t2) est utilisée pour contraindre t1 et t2 à représenter toujours des objets différents. Dès que cette contrainte ne peut plus être satisfaite, on revient en arrière (backtracking). L’implantation de dif utilise un mécanisme similaire à geler.
Voici deux primitives intéressantes que l’on peut écrire avec dif : hors_de(x, l) qui vérifie que x n’appartiendra jamais à la liste l; et tous_differents(l) qui vérifie que les composants de la liste l seront toujours différents deux à deux.
hors_de(x, nil) -> ;
hors_de(x, y.l) -> dif(x, y) hors_de(x, l);
tous_differents(nil) -> ;
tous_differents(x.l) -> hors_de(x, l)
tous_differents(l);
Avec ces deux primitives on peut par exemple écrire un programme qui calcule des permutations : il suffit de dire que l’on a une liste d’entiers et que tous les éléments de cette liste sont différents deux à deux :
permutation(x1,x2,x3,x4) ->
tous_differents(x1.x2.x3.x4.nil)
chiffre(x1) chiffre(x2) chiffre(x3) chiffre(x4);
chiffre(1) -> ;
chiffre(2) -> ;
chiffre(3) -> ;
chiffre(4) -> ;
Remarquons que dans cet exemple, Prolog met d’abord en place toutes les inégalités avant d’exécuter le programme non-déterministe classique. Ceci donne une programmation plus claire et plus efficace.
L’utilisation de dif permet également l’ écriture de programmes qui auraient un comportement incorrect si l’on utilisait une définition utilisant la coupure. Par exemple la définition de la relation « x est élément de l à la valeur v » peut s’écrire :
élément(x,nil,false) ->; élément(x,x.l,true) ->; élément(x,y.l,v) -> dif(x,y) élément(x,l,v);
élément(x,1.2.nil,v); {x=1, v=true}
{x=2, v=true}
{x#1, x#2, v=false}
Si l’on définissait une telle relation en utilisant la primitive !, on introduirait de nombreux comportements anormaux :
élément(x,nil,false) ->;
élément(x,x.l,true) -> ! ;
élément(x,y.l,v) -> élément(x,l,v);
> élément(x,1.2.nil,v);
{x=1, v=true} % une seule solution !!
> élément(2,4.2.3.nil,false);
{} % succès !!
default(t1, t2)
La règle prédéfinie default permet de réaliser le contrôle suivant: Si on peut effacer t1, alors on l’efface de toutes les manières possibles, sinon on efface t2. Il faut remarquer que contrairement à ce que l’on pourrait penser à première vue, cette primitive ne peut pas être réalisée avec ‘!’. Voyons sur un exemple une utilisation de cette règle:
répondre(p) -> default(p,outml(« personne »));
homme(jean) ->;
homme(pierre) ->;
répondre(homme(x));
{x=jean}
{x=pierre}
répondre(femme(x)); personne
{}
eq(t1, t2)
Unification de t1 et t2 : correspond simplement à la règle :
eq(x,x) -> ; .
fail
Règle prédéfinie provoquant toujours un échec (backtracking).
findall(x, p, l)
Unifie l avec la liste de toutes les solutions x lorsqu’on efface p.
free(x)
S’efface uniquement si x n’est pas lié.
list_of(x, y, p, l)
Fournit la liste triée, sans répétition, de tous les individus qui satisfont une certaine propriété.
x est une variable.
y est une liste de variables.
p est un terme Prolog contenant au moins toutes ces variables.
Pour chaque ensemble de valeurs de y, unifie l avec la liste des valeurs de x pour que p soit vraie (c’est à dire pour que p s’efface).
L’ordre de la liste l est identique à celui défini sur les termes (cf. term_cmp/3)
Exemple : Prolog contenant la base de règles suivante :
homme(grand, michel, 184) ->;
homme(grand, alain, 183) ->;
homme(grand, henry, 192) ->;
homme(petit, nicolas, 175) ->;
homme(petit, julien, 176) ->;
homme(petit, gilles, 120) ->;
list_of(x,t.nil,homme(t,x,h),l); {t=grand, l=alain.henry.michel.nil} {t=petit, l=gilles.julien.nicolas.nil}
not(X)
Est décrit par les règles:
not(X) :- X,!,fail.
not(X).
repeat
Est décrit par les règles :
repeat ->;
repeat -> repeat;
setof(x, p, l)
Pour chaque instantiation différente de l’ensemble des variables libres du but p, non existentielles et n’apparaissant pas dans le terme x, unifie l avec la liste de toutes les solutions x lorsqu’on efface p . Chaque liste l est triée et sans répétition. L’ordre de la liste l est identique à celui défini sur les termes (cf. term_cmp/3).
Exemple : Prolog contenant la base de règles suivante :
aa(2,1) -> ;
aa(1,2) -> ;
aa(1,1) -> ;
aa(2,2) -> ;
aa(2,1) -> ;
setof(X, aa(X,Y),L); {Y=1, L= 1.2.nil} {Y=2, L= 1.2.nil}
setof(X,Y^aa(X,Y),L);
{L=1.2.nil}
or(x,y)
Définit un ou logique transparent à la coupure. Exemple:
op(900,xfy,or);
{}
enum(i,4) (eq(i,1) or eq(i,2)); {i=1}
{i=2}
enum(i,4) ([eq(i,3),’!’] or [outl(no),fail]);
no no {i=3}
Geler
Il s’agit de résoudre de manière efficace un problème qui se pose souvent en Prolog : retarder le plus possible certaines décisions. Ce qui revient à dire qu’il faut avoir suffisamment d’information avant de poursuivre l’exécution d’un programme, ou que certaines variables doivent avoir reçu une valeur pour pouvoir continuer. On profite alors des avantages de la programmation déclarative, tout en gardant une exécution efficace.
freeze(x, q)
Le but de cette règle prédéfinie est de retarder l’effacement de q tant que x est inconnu. Plus précisément :
Si x est libre, alors freeze(x, q) s’efface et l’effacement de q est mis en attente (on dit que q est gelé). L’effacement effectif de q sera déclenché au moment où x deviendra liée.
Si x est liée alors freeze lance l’effacement de q normalement.
C’est au programmeur de s’assurer qu’une variable gelée sera toujours dégelée dans le futur, pour que le but associé ne reste pas indéfiniment en attente. Ceci n’est pas vérifié par Prolog, et peut conduire à des solutions trop générales.
Remarque : Les impressions des variables d’une question sur lesquelles il reste des buts gelés se fait d’une manière spéciale :
freeze(x,foo);
{x~foo.nil}
Voyons maintenant quelques exemples d’utilisation de freeze.
Exemple 1 : Evaluation de somme(x, y, z). On veut résoudre l’équation z = x + y seulement si les deux variables x et y sont connues.
somme(x, y, z) -> freeze(x, freeze(y, somme1(x, y, z))) ; somme1(x, y, z) -> val(x+y, z);
Exemple 2 : Mais on peut faire mieux : On veut résoudre la même équation si deux au moins des variables x, y, z sont connues :
somme (x, y, z) ->
freeze(x, freeze(y, ou_bien(u, somme1(x, y, z)))) freeze(y, freeze(z, ou_bien(u, somme2(x, y, z)))) freeze(x, freeze(z, ou_bien(u, somme3(x, y, z))));
ou_bien(u, p) -> free(u) ! eq(u, Cst) p;
ou_bien(u, p) ->;
somme1(x, y, z) -> val(x+y, z);
somme2(x, y, z) -> val(z-y, x);
somme3(x, y, z) -> val(z-x, y);
Ci-dessus, la variable u, qui devient liée dès que l’une des additions est effectuée, sert à empêcher que les autres additions, redondantes, soient calculées.
Exemple 3 : Cet exemple montre comment utiliser une variable pour contrôler un programme de l’extérieur. La règle liste_de_un qui a été donnée dans un exemple précédent, bouclait. Pour empêcher cette boucle on utilise simplement une condition externe : longueur(l, n) qui vérifie que la longueur d’une liste l est inférieure ou égale à n.
longueur(l,n) -> freeze(l,longueur'(l,n)); longueur'(nil, n) ->;
longueur'(e.l, n) ->
dif(n,0) val(n-1, n’) longueur(l, n’);
liste_de_un(1.x) -> liste_de_un(x);
liste_de_un(nil) -> ;
longueur(l,5) liste_de_un(l); {l=1.1.1.1.1.nil} {l=1.1.1.1.nil} {l=1.1.1.nil}
{l=1.nil}
{l=nil}
Quand tous les buts ont été effacés, il se peut qu’il reste encore certains buts gelés sur des variables qui sont encore libres.
Remarque : Les optimisations de compilation ne permettent pas de déclencher les buts gelés dès l’unification de la tête de règle mais seulement sur le premier but de la queue non optimisé. En particulier, l’exemple suivant échouera :
insert;
nombre(<i>) -> integer(i);
lier(<1>) ->;;
{}
freeze(x, lier(x)) nombre(x);
>
En effet, les prédicats de test de type étant optimisés, le dégel de lier(<i>) ne se fera pas puisqu’il n’y a pas d’autres buts dans la queue de nombre/1.
A propos des arbres infinis
Ce paragraphe donne quelques informations pratiques sur l’utilisation dans Prolog II des arbres infinis. Tout d’abord, il faut remarquer qu’un certain nombre de règles prédéfinies ne travaillent que sur des arbres finis. En particulier, in ne peut pas lire d’arbres infinis, et assert ne peut pas ajouter de règles contenant des arbres infinis.
infinite
no_infinite
Ces règles servent à définir le type d’impression de résultat utilisé: il faut avoir activé l’option infinite si l’on désire imprimer des solutions contenant des arbres infinis.
Voici un exemple qui utilise freeze et qui vérifie qu’un arbre est toujours fini. Ceci est un moyen indirect de faire le test dit d’occur_check. Ce programme vérifie que l’on n’a pas deux fois le même sous-arbre dans chaque branche de l’arbre.
arbre_fini(x) -> branche_finie(x, nil);
branche_finie(x, l) -> freeze(x, branche_finie'(x, l));
branche_finie'(x, l) ->
hors_de(x, l) domine (x, l’) branches_finies(l’, x.l);
branches_finies(nil, l) -> ;
branches_finies(x.l’, l) ->
branche_finie (x, l) branches_finies (l’, l) ; domine(x1.x2, x1.x2.nil) -> ! ;
domine(x, x’) -> tuple(x) ! split(x, x’) ; domine(x, nil) -> ;
infinite_flag
Symbole dont la valeur (0 ou 1) indique si infinite ou no_infinite est actif.
Cette valeur peut être testée par l’intermédiaire de la règle prédéfinie val.
equations(t, t’, l)
Cette règle prédéfinie sert à transformer un arbre fini ou infini t en une liste d’équations l qui a comme solution t. t’ indique la variable de l représentant la racine de l’arbre t. C’est cette primitive qui est utilisée pour imprimer les solutions lorsque l’option infinite est active. Regardons une utilisation sur l’exemple suivant :
infinite eq(x,ff(ff(x))) equations(x,t’,l) out(t’) outm( » : « ) outl(l) ;
v131 : eq(v131,ff(v131)).nil
{x=v131, v131=ff(v131), l=eq(t’,ff(t’)).nil}
eq(x,ff(ff(x)));
{x=v120,v120=ff(v120)}
Mais une des utilisations principales de cette primitive est le fait de pouvoir ajouter des arbres infinis. Nous utilisons la primitive assert (chapitre suivant) qui permet d’ajouter une règle.
ajout_infini(t) ->
equations(t,t’,l)
assert(arbre(t’),l) ;
infinite eq(x, ff(ff(x))) ajout_infini(x) ; {x=v131, v131=ff(v131)}
list(arbre/1) ;
arbre(x11) -> eq(x11, ff(x11)) ;
{}
> arbre(x) ;
{x=v131, v131=ff(v131)}
Quelques conseils pour la programmation récursive
Le système Prolog II+ comporte un récupérateur de mémoire (garbage collector) automatique. Ce « ramasse-miettes » est très performant et est capable de ne garder dans les piles que les données dont vous avez effectivement besoin; ceci permet d’utiliser à fond les définitions récursives de programmes. Malgré tout, certaines techniques de programmation peuvent vous aider à récupérer encore plus d’espace. Pratiquement, il s’agit d’utiliser adroitement la coupure des points de choix ainsi que de tirer un maximum de profit de l’optimisation de récursion et d’appel terminal que fait le compilateur Prolog II+. L’utilisation de ces techniques permet l’écriture de programmes qui se rappellent eux-mêmes indéfiniment, sans jamais déborder.
Introduction
Standardisation
Performances
Modularité
Ouverture vers l’extérieur
0. Débuter avec Prolog
0.1. Leçon 1 : Lancement de Prolog
0.2. Leçon 2 : Utilisation d’un programme d’exemple
0.3. Leçon 3 : L’Editeur
0.4. Les erreurs les plus courantes
0.4.1. Débordement de l’espace de code
0.4.2. Interruption.
0.4.3. Erreurs détectées en cours d’insertion
0.4.4. Erreurs concernant les fichiers.
0.4.5. Erreurs de syntaxe
0.4.6. Erreurs d’exécution
1. Eléments de base
1.1. Notations utilisées
1.2. Jeu de caractères
1.3. Les variables
1.4. Constantes
1.5. Termes et arbres
1.6. Les opérateurs
1.7. Les règles et les assertions
1.8. Les mécanismes de base de Prolog
1.9. La syntaxe complète de Prolog II+
1.10. Le macroprocesseur
2. Le contrôle
2.1. Le contrôle
2.2. Geler
2.3. A propos des arbres infinis
2.4. Quelques conseils pour la programmation récursive
2.5. Les meta-structures
2.5.1. Création
2.5.2. Récupération
2.5.3. Unification forcée
2.5.4. Sorties
2.5.5. Exemple
3. Structuration des règles
3.1. Introduction
3.2. Terminologie
3.3. Syntaxe des identificateurs
3.3.1. Paramétrage de l’écriture d’un identificateur complet ….R 3 – 7
3.4. Contexte de Lecture et Ecriture
3.5. Modules
3.5.1. Définition d’un module
3.5.2. Module source
3.5.3. Module Objet
3.6. Résumé ou Approche simplifiée des identificateurs, contextes et modules
3.7. Ajout, suppression et recherche de règles
3.8. Manipulation des modules compilés
4. Opérations prédéfinies
4.1. Les tests de type
4.2. Les opérations arithmétiques
4.3. Affectation
4.4. Opérations sur les chaînes
4.5. Composition et décomposition d’objets
4.6. Comparaison de termes quelconques
5. Les entrées / sorties
5.0. Généralités
5.1. Entrées
5.1.1. Règles pour l’entrée
5.1.2. Modification de l’unité d’entrée
5.2. Sorties
5.3. Chargement et adaptation du module de dessin
5.4. Déclaration d’opérateurs
6. L’environnement
6.1. Comment sortir de Prolog
6.2. Démarrage automatique d’un programme Prolog
6.3. Edition de programmes
6.4. Date, temps et mesures
6.5. Lien avec le système
6.6. Outil de mise au point de programmes
6.7. Modification et visualisation de l’état courant
6.8. Gestion automatique des espaces et des piles
7. Extensions de Prolog avec des langages externes.
7.1. Principes des fonctions de communication de données
7.2. Fonctions de communication de données simples
7.3. Fonctions de communication de termes quelconques
7.4. Principe de la méthode des descripteurs
7.5. Données partagées
7.5.1. Exemple de zone commune de données
7.6. Ajout de fonctions externes
7.6.1. Exemple de déclaration de règle prédéfinie
7.7. Ajout de fonctions externes à appel direct
8. Lancement d’un but Prolog par un programme C
8.1. Principes de base
8.2. Initialisation et terminaison de Prolog
8.3. Empilement d’un but Prolog
8.4. Programmation
8.5. Méthode simple d’appel d’un but Prolog
8.6 Autres fonctions
9. Interruptions
9.1. Concepts
9.2. Description des interfaces
9.3. Exemple complet
10. Extensions Edinburgh
10.1. Syntaxe
10.2. Le contrôle
10.3. Manipulation des règles
10.4. Opérations prédéfinies sur les données
10.5. Les entrées / sorties
10.6. L’environnement
10.7. Traduction de DCG