Le langage Prolog


précédentsommaire

4. Conseils pratiques

... sur le langage

Unification et variables libres

On présente souvent l'opération suivante:

 
Sélectionnez
predicat(X, X) :- ...

comme une comparaison entre les 2 paramètres du prédicat. C'est faux !

En fait, ce prédicat est équivalent à :

 
Sélectionnez
predicat(X, Y) :- X=Y, ...

Si X et Y sont tous deux des variables liées (c'est-à-dire pour lesquelles on a affecté une valeur), alors l'opération se comportera comme une comparaison. Si en revanche l'une au moins des 2 variables est libre, alors l'opération procédera à une unification entre X et Y. Ceci pose d'énormes problèmes lorsque l'on travaille sur des variables libres (par exemple, en Programmation Logique avec Contraintes)

Pour faire une comparaison sur des valeurs, il faut utiliser l'opérateur ==, l'opérateur = étant réservé à l'unification.

L'opérateur Not (\+)

L'opérateur Not (\+) permet la négation d'un prédicat.

Attention cependant, ceci n'a de sens que si les variables passées en paramètres au prédicat sont TOUTES unifiées.

En aucun cas un prédicat villesDifferentes/2 qui serait la négation de memeVille/2 ne renverrait l'ensemble des valeurs qui n'appartiendraient pas à la relation memeVille. Tout ce que le prédicat villesDifferentes/2 pourrait faire, c'est vérifier que deux personnes spécifiques habitent dans la deux villes différentes. C'est tout !

Le plus simple pour avoir la liste des personnes qui habitent dans des villes différentes est d'écrire un prédicat spécifique en adaptant le prédicat memeVille/2.

Cette erreur est courante chez les débutants.

Prédicats dynamiques et records

Prolog permet d'ajouter, d'enlever une ou toutes les clauses ou même de supprimer complètement un prédicat, et ce de manière dynamique, grâce aux prédicats assert/1, asserta/1, retract/1, retractAll/1, abolish/1 et abolish/2.

Exemple:

 
Sélectionnez
% Ajoute le fait que Julie habite à Lille
assert( habite(julie, lille) ).

La différence entre assert/1 et asserta/1 est que asserta/1 ajoute la clause en début de prédicat alors que assert/1 ajoute la clause en fin de prédicat (synonyme: assertz/1)

Ce mécanisme se révèle extrêmement pratique: le Prolog se comporte comme une base de données dans laquelle il est facile d'ajouter ou d'enlever des clauses en cours d'exécution (sans avoir à définir de structure de données particulière). L'avantage est que la consultation de ces clauses est extrêmement rapide, puisqu'elles font alors partie du programme. L'inconvénient est que l'ajout/suppression de ces clauses est couteuse en termes de temps.

Si vous essayez de faire appel à un prédicat qui n'existe pas (ou de modifier les clauses d'un prédicat non dynamique), Prolog retournera une erreur. Il est donc necessaire de déclarer au préalable les prédicats dynamiques comme ceci:

:- dynamic( prédicat/arité).

Exemple:

 
Sélectionnez
:- dynamic( habite/2 ).



Une autre manière de procéder pour avoir des relations dynamiques est d'utiliser un record. Un record associe une clef à une valeur. Ainsi il est possible de faire :

 
Sélectionnez
recorda( habiteLille, julie ).

pour associer Julie à la clef habiteLille. On utilise le prédicat recorded(+Clef, -Valeur) pour récupérer les valeurs associées à une clef particulière.

Cette manière de faire est beaucoup moins expressive que la précédente (on associe juste des clefs à des valeurs alors que dans l'autre cas on redéfinit des clauses) et donc ne répondra pas à tous les besoins. Elle est cependant plus rapide car les données sont stockées en mémoire.

L'instruction findall

En Prolog, il est possible d'obtenir une liste de toutes les solutions d'un prédicat grâce au prédicat findall :

Execution
Sélectionnez
| ?- findall(X, habite(X,paris), R).   
R = [lucie,adeline,nicolas] ?


Execution
Sélectionnez
| ?- findall((X,Y), memeVille(X,Y), R).                                
R = [(lucie,adeline), (lucie,nicolas), (adeline,lucie), (adeline,nicolas), (nicolas,lucie), (nicolas,adeline)] ?



Pour plus d'informations sur le prédicat findall (ainsi que sur les prédicats bagof et setof), voir cet article :
Prédicats findall, bagof et setof

Les opérateurs en Prolog

Prolog comprend de nombreux opérateurs arithmétiques, parmi lesquels:

+(X) Plus X
-X Moins X
X+Y Addition
X-Y Soustraction
X*Y Produit
X/Y Division (flottant)
X//Y Division entière
X mod Y Modulo (reste de la division entière)
float(X) Entier le plus proche de X compris entre 0 et X
X/\Y ET bit-à-bit
X\/Y OU bit-à-bit
X#Y OU EXCLUSIF bit-à-bit
\(X) Inversion des bits de X (complément à 1)
X<<Y Décalage de Y bits de X vers la gauche
X>>Y Décalage de Y bits de X vers la droite

 
X=Y Unification
X==Y Egal
X\=Y Différent
X<Y Inférieur
X>Y Supérieur
X=<Y Inférieur ou égal
X>=Y Supérieur ou égal



Moyen mnémotechnique : L'opérateur "Inférieur ou égal" est différent de celui du C ou Java, par exemple. Pour éviter toute confusion, il suffit de se rappeller qu'en Prolog, les opérateurs "Inférieur/Supérieur ou égal" ne forment jamais une flêche.

... sur l'environnement de développement

Les modules

Comme dans tout langage qui se respecte, il est possible d'organiser ses sources en modules et de préciser quelles fonctions sont accessibles depuis l'extérieur.

On déclare un module en ajoutant dans l'entête du fichier:

 
Sélectionnez
:- module(didactitiel, [habite/2]).

Le premier argument est le nom du module. Le deuxième argument est la liste de tous les prédicats accessibles par le module appelant (sous la forme prédicat/arité ).

Pour appeler un module, on ajoute la ligne:

 
Sélectionnez
:- use_module(nomModule).

Le danger des "consult" successifs

Pour charger un programme Prolog, on utilise le prédicat consult avec comme argument le chemin d'accès du programme, sous forme d'une chaîne :

Exécution
Sélectionnez
| ?- consult('foo.pro').

Tous les prédicats sont alors évalués et on peut alors les exécuter.

Lorsque l'on développe en Prolog, on est souvent amené à modifier notre programme et donc à recharger le code source. Ce faisant, les prédicats ayant été modifiés sont remplacés par les nouveaux, alors que les autres prédicats restent en mémoire. Si un prédicat a été supprimé dans le fichier source, il reste en mémoire et les prédicats appelant semblent marcher. Il peut donc rester des traces des anciens chargements dans l'environnement de développement.

Le plus simple pour éviter ce problème est de régulièrement tester vos programmes en développement dans un environnement vierge de tout chargement antérieur.

Voilà, ce didacticiel nous a donné une bonne idée des possibilités de Prolog et a permis de
comprendre certains de ses mécanismes afin de les exploiter au mieux.

Le reste est une question de pratique !

précédentsommaire

  

Copyright © 2006 pcaboche. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.