Premiers pas avec le langage Prolog

Programmation de la base de données

Prolog catégorise tout en :

  • Atomes - Toute séquence de caractères qui ne commence pas par un alphabet majuscule. Par exemple - ‘a’, ‘b’, ’d’accord’
  • Numéros - Il n’y a pas de syntaxe spéciale pour les nombres, aucune déclaration n’est requise. Par exemple, 1, 22, 35.8
  • Variables - Une chaîne commençant par une majuscule ou un trait de soulignement (_). Par exemple, ‘X’, ‘Y’, ‘Abc’, ‘AA’
  • Termes complexes - Ils sont constitués d’un foncteur et d’une suite d’arguments. Le nom d’un terme complexe est toujours un atome, tandis que les arguments peuvent être des atomes ou des variables. Par exemple, père(jean, biche), parent(e), mère(X,Y).

Une base de données logique contient un ensemble de faits et de règles.

Un terme complexe avec uniquement des atomes comme arguments est appelé un fait, tandis qu’un terme complexe avec des variables comme arguments est appelé une règle.

Exemple de faits en Prolog :

father_child(fred, susan).
mother_child(hillary, joe).

Exemple de règle en Prolog :

child_of(X,Y):-
    father_child(Y,X)
    ;
    mother_child(Y,X).

Notez que le ; ici est comme l’opérateur or dans d’autres langages.

Prolog est un langage déclaratif et vous pouvez lire cette base de données comme suit :

fred est le père de susan

Hillary est la mère de Joe.

Pour tout X et Y, X est un enfant de Y si Y est père de X ou Y est mère de X.

En fait, un ensemble fini de faits et ou de règles constitue un programme logique.

L’utilisation d’un tel programme est démontrée en faisant des requêtes. Les requêtes vous permettent de récupérer des informations à partir d’un programme logique.

Pour charger la base de données dans l’interpréteur (en supposant que vous avez enregistré la base de données dans le répertoire dans lequel vous exécutez l’interpréteur), vous entrez simplement :

?- [nameofdatabase].

en remplaçant le nameofdatabase par le nom de fichier réel (notez qu’ici nous excluons l’extension .pl du nom de fichier).

Exemple de requêtes dans l’interpréteur pour le programme ci-dessus et les résultats :

?- child_of(susan,fred).
true

?- child_of(joe,hillary).
true

?- child_of(fred,susan).
false

?- child_of(susan,hillary).
false

?- child_of(susan,X).
X = fred

?- child_of(X,Y).
X = susan,
Y = fred ;
X = joe,
Y = hillary.

Les questions ci-dessus et leurs réponses peuvent être lues comme suit :

Susan est-il un enfant de Fred ? - vrai

Joe est-il un enfant d’Hillary ? - vrai

est-ce que fred est un enfant de susan ? - faux

Susan est-il un enfant d’Hillary ? - faux

de qui susan est-elle l’enfant ? - Fred

C’est ainsi que nous programmons la logique en Prolog. Un programme logique est plus formellement : un ensemble d’axiomes, ou de règles, définissant des relations (c’est-à-dire des prédicats) entre des objets. Une autre façon d’interpréter la base de données ci-dessus d’une manière logique plus formelle est :

La relation “père_enfant” tient entre fred et susan

La relation mother_child tient entre hillary et joe

Pour tous X et Y la relation child_of est vraie entre X et Y si la relation father_child est vraie entre Y et X, ou la relation mother_child est vraie entre Y et X.

Bonjour le monde

Hello, World dans l’interpréteur interactif

Pour imprimer “Hello, World!” dans l’interpréteur Prolog (ici, nous utilisons swipl, le shell pour SWI Prolog):

$ swipl
<...banner...>
?- write('Hello, World!'), nl.

?- est l’invite système : elle indique que le système est prêt à ce que l’utilisateur entre une séquence de buts (c’est-à-dire une requête) qui doit se terminer par un . (point).

Ici, la requête write('Hello World!'), nl a deux objectifs :

  • write('Hello World!') : 'Hello World!' doit être affiché et (,)
  • une nouvelle ligne (nl) doit suivre.

write/1 (le /1 est utilisé pour indiquer que le prédicat prend un argument) et nl/0 sont des prédicats intégrés (la définition est fournie à l’avance par le système Prolog). Les prédicats intégrés fournissent des fonctionnalités qui ne peuvent pas être obtenues par une définition Prolog pure ou pour éviter au programmeur d’avoir à les définir.

Le résultat:

Bonjour, Monde !

oui

se termine par “oui” signifiant que la requête a réussi. Dans certains systèmes, “true” est imprimé à la place de “yes”.

Hello, World à partir d’un fichier

Ouvrez un nouveau fichier appelé hello_world.pl et insérez le texte suivant :

:- initialization hello_world, halt.

hello_world :-
    write('Hello, World!'), nl.

La directive initialization spécifie que le goal hello_world, halt doit être appelé lorsque le fichier est chargé. halt quitte le programme.

Ce fichier pourra ensuite être exécuté par votre exécutable Prolog. Les drapeaux exacts dépendent du système Prolog. Si vous utilisez SWI Prolog :

$ swipl -q -l hello_world.pl 

Cela produira la sortie Hello, World!. Le drapeau -q supprime la bannière qui s’affiche généralement lorsque vous appelez run swipl. Le -l spécifie un fichier à charger.

Installation ou configuration

SWI-Prolog

Windows et Mac :

  • Téléchargez SWI-Prolog sur le site officiel
  • Installez simplement en suivant les instructions d’installation.

Linux (PPA):

  • Ajoutez le PPA ppa:swi-prolog/stable aux sources logicielles de votre système (les développeurs peuvent choisir ppa:swi-prolog/devel) :

    • Open a terminal (Ctrl+Alt+T) and type: sudo add-apt-repository ppa:swi-prolog/stable

    • Afterwards, update the package information: sudo apt-get update

  • Installez maintenant SWI-Prolog via le gestionnaire de packages : sudo apt-get install swi-prolog

  • Vous pouvez maintenant démarrer SWI-Prolog via la ligne de commande avec la commande swipl

ajouter/3

append([], Bs, Bs).
append([A|As], Bs, [A|Cs]) :-
    append(As, Bs, Cs).

append/3 est l’une des relations Prolog les plus connues. Il définit une relation entre trois arguments et est vrai si le troisième argument est une liste qui dénote la concaténation des listes qui sont spécifiées dans les premier et deuxième arguments.

Notamment, et comme c’est généralement le cas pour un bon code Prolog, append/3 peut être utilisé dans plusieurs directions : il peut être utilisé pour :

  • append deux listes entièrement ou partiellement instanciées :

      ?- A = [1, 2, 3], B=[4, 5, 6], append(A, B, Y)
      Output:
      A = [1, 2, 3],
      B = [4, 5, 6],
      Y = [1, 2, 3, 4, 5, 6].
    
  • vérifier si la relation est vraie pour trois listes entièrement instanciées :

      ?- A = [1, 2, 3], B = [4, 5], C = [1, 2, 3, 4, 5, 6], append(A, B, C)
      Output:
      false
    
  • générer toutes les manières possibles d’ajouter deux listes à une liste donnée :

      ?- append(A, B, [1, 2, 3, 4]).
      Output:
      A = [],
      B = [1, 2, 3, 4] ;
      A = [1],
      B = [2, 3, 4] ;
      A = [1, 2],
      B = [3, 4] ;
      A = [1, 2, 3],
      B = [4] ;
      A = [1, 2, 3, 4],
      B = [] ;
      false.
    

Contraintes CLP(FD)

Les contraintes CLP(FD) sont fournies par toutes les implémentations sérieuses de Prolog. Ils nous permettent de raisonner sur des entiers de manière pure.

?- X #= 1 + 2.
X = 3.

?- 5 #= Y + 2.
Y = 3.