Attention : ce tuteur PROLOG utilise le langage Turbo-PROLOG qui n'existe plus et qui n'est un "vrai" PROLOG à cause du typage...Introduction Prolog est un langage interprété compilable basé sur l'évaluation d'expressions logiques (PROgrammation LOGique). Contrairement aux langages classiques comme Pascal ou C, il permet de calculer, de vérifier et de déduire avec la même syntaxe. En Prolog, on écrit des prédicats. Ils sont définis par des faits et/ou des règles. Pour les utiliser, on indique un but à satisfaire ("un problème à résoudre"). Le langage dispose d'une mécanisme nommé résolution qui lui permet de "naviguer" entre les diverses possibilités. Lors d'"essais" le langage peut donner des valeurs aux variables. Il ne s'agit pas alors de véritable affectation mais d'instanciation. Le langage peut aussi revenir en arrière sur ses choix et "libérer" les variables avant de faire de nouveaux choix. Un exemple classique est celui de la description de relations familiales. On écrira fils(Jean,Dani). fils(Paul,Dani). fille(Isa,Pierre). fille(Brigitte,Dani). ... pour indiquer que Jean est le fils de Dani, Isa la fille de Pierre, etc. Il s'agit de faits qui mettent en jeu les prédicat fils et fille. On peut définir la notion de fraternité par la règle : "deux persones sont frères s'ils sont fils de la même mère", soit encore, en Prolog, avec le prédicat frere : frere(x,y) :- fils(x,m) and fils(y,m). Ici, x,y, et m sont des variables alors que Jean et Dani étaient des symboles. L'utilisation des prédicats précédents se fait par satisfaction de but. 1 - En vérification, on peut poser comme but fils(Jean,Isa) ce qui signifie "Jean est-il le fils d' Isa ? ". La réponse est non, compte tenu des faits fournis. 2 - En recherche, on peut poser comme but fils(Jean,_) ce qui signifie "de qui Jean est-il le fils ? ". La réponse est Dani, compte tenu des faits fournis. Le langage se contente d'effectuer des déductions logiques. Il n'est pas responsable des incohérences logiques ou des erreurs de programmation. Ainsi, avec le fait fils(Jean,Voiture). on peut déduire que Jean est le fils d'une voiture ! De même, si on définit le prédicat memeParent(x,y) :- filsentier (x,m) and fille(y,m). on peut déduire que Jean et Brigitte (dans cet ordre) ont un même parent, mais pas Brigitte et Jean. Cela tient au fait que Prolog "unifie" les variables en tenant compte de l'ordre des termes, ce qui parait raisonnable. Il serait donc prudent ici de rajouter une deuxième règle pour définir memeParent : memeParent(x,y) :- fils(y,m) and fille(x,m). L' écriture de prédicats récursifs en Prolog est l'unique moyen de réaliser des boucles. Le prédicat somme défini par somme(0,0). somme(n,s) :- np := n-1 and somme(np,sp) and s := sp + n. calcule pour n donné la somme (nommée s) des n premiers entiers. De même, si on définit les prédicats mere(x,y), pere(x,y) on peut définir : parent(x,y) :- pere(x,y). parent(x,y) :- mere(x,y). ancetre(x,y) :- parent(x,y). ancetre(x,y) :- parent(x,t) and ancetre(t,y). Le choix des prédicats est délicat. Un prédicat d'arité n (c'est -à-dire avec n paramètres) peut toujours être injecté comme le paramètre numéro n+1 d'un prédicat plus général. Ainsi, on aurait pu définir le prédicat lie(Jean,Dani,fils) qui permet de réponde à la question "qu'est-ce qui lie jean et Dani ?". Un autre exemple est celui des propriétés : au lieu de définir des faits comme rouge(ballon), rond(ballon) etc. il peut être plus intéressant de définir est(ballon, rouge) et est(ballon,rond) car on peut alors trouver ce que le ballon est (ce que ne permettaient pas les prédicats rouge et rond). Une liste regroupe des éléments de même nature. La liste vide se note [] et une liste qui contient a,b,c... se note [a,b,c...]. Dans une liste, on distingue le début (ou tête) et la fin (ou queue). La tête est le premier élément de la liste. La séparation entre tête et queue se fait par |. Ainsi, l'unification de la liste [a,b,c] avec [X|Y] est réalisée si X=a et si Y=[b,c]. Comme en Lisp, la récursivité est un outil adapté à la gestion des listes. A titre d'exemple : longueur( [] , 0 ) . longueur( [X|Y], Z ) :- longueur( Y, Lp ) and Z = Lp + 1. sommeListe( [] , 0 ) . sommeListe( [X|Y], Z ) :- sommeListe( Y, Sp ) and Z = Sp + X. Le mécanisme de la coupure permet notamment à Prolog de "geler" des choix, pour éviter un retour arrière. Par exemple, tous les humains sauf Adam et Eve ont deux parents. Définir nbParents(eve,0). nbParents(adam,0). nbParents(X,2). est insufissant car nbParents(eve,n) peut être satisfait par les assertions 1 et 3. La coupure notée ! permet d'arrêter Prolog dans ses recherches. On écrira donc nbParents(eve,0) :- !. nbParents(adam,0) :- !. nbParents(X,2). De nombreux prédicats prédéfinis sont disponibles. En Turbo Prolog, par exemple, write(c) écrit la chaine c à l'écran (sans retour charriot), nl effectue un retour charriot, fronttoken(a,b,c) est satisfait si a est la concaténation de b et c, circle(x,y,r) trace un cercle de centre (x,y) et de rayon r etc. De plus, Turbo Prolog utilise le typage pour faciliter la compilation. Le modèle d'un fichier de prédicats est exemple domains liste=real* predicates longueur(liste,integer) clauses longueur([],0). longueur(...