• Aucun résultat trouvé

Pour désigner des arbres qui ne sont pas des constantes vous devez écrire des formules qui combinent des constantes et des opérateurs, selon une syntaxe que nous indiquerons progressivement. Une telle formule exprime le résultat d'une opération. Une opération est définie sur un ensemble de n-

uplets d'arbres ; à chacun elle associe un arbre1 :

f : (a1, … an) ! f (a1, … an)

L'ensemble des n-uplets d'arbres pour lesquels une opération donnée est définie n'est pas obligatoirement égal à l'ensemble de tous les n-uplets ; on dit que l'opération est partielle. Spécifier le sous-ensemble des n-uplets sur lesquels l'opération est définie fait partie de la définition de l'opération en question.

On dispose de trois types d'opérations : les opérations booléennes, les opérations arithmétiques et les opérations de construction d'arbres. Avec une précision importante: les opérations booléennes et arithmétiques ont leur

signification mathématique habituelle.

Cette remarque peut surprendre mais elle mérite d'être faite, notamment à l'intention des utilisateurs des Prolog précédents. Dans ces langages, des opérations notées +, *, &, etc… sont définies ou pourraient l'être ; cepen- dant, elles n'y ont pas leur signification mathématique courante, elles ne sont que des opérations de construction d'arbres. Ainsi, en Prolog II, la formule

2 + 3 désigne l'arbre dont l'étiquette est + et les fils 2 et 3. Un prédicat prédéfini peut ensuite interpréter cet arbre et en extraire le nombre 5, mais cela est étranger au cœur de Prolog II, qui n'effectue aucun traitement spécifique des booléens ou des nombres.

1 Dans le jargon mathématique, une opération est donc une application

En Prolog III, au contraire, les opérations booléennes et arithmétiques sont connues en tant que telles du cœur du langage, qui leur donne leur signification logique ou arithmétique habituelle. Il en découle que l'arbre représenté par la formule 2 + 3 n'est autre que la feuille réduite au nombre 5, résultat de l'opération indiquée.

Cette remarque aura encore plus d'intérêt quand nous considérerons les termes avec des variables. Comme pour l'addition précédente, la formule 2 + X ne désignera pas un quelconque arbre non atomique mais bel et bien le nombre (inconnu) résultat de l'addition de 2 et du nombre inconnu X.

Opérations booléennes

Les opérations booléennes ne sont définies que si les opérandes sont des valeurs booléennes, c'est-à-dire des feuilles étiquetées par des constantes booléennes.

(1) L'opération unaire non

a1 ! ~ a1

(2) L'opération binaire et (a1, a2) ! a1& a2

(3) L'opération binaire ou (non exclusif) (a1, a2) ! a1| a2

(4) L'opération binaire implique (a1, a2) ! a1=> a2

(5) L'opération binaire équivalent (a1, a2) ! a1 <=> a2

Les résultats rendus par ces différentes opérations sont définis par le tableau suivant :

a1 a2 ~a2 a1& a2 a1| a2 a1=> a2 a1 <=> a2

0 ' 0 ' 1 ' 0 ' 0 ' 1 ' 1 ' 0 ' 1 ' 0 ' 0 ' 1 ' 1 ' 0 '

1 ' 0 ' 0 ' 1 ' 0 ' 0 '

1 ' 1 ' 1 ' 1 ' 1 ' 1 '

Des termes corrects exprimant des opérations booléennes, ainsi que certaines fautes à ne pas commettre, sont montrés au § 5.

Opérations arithmétiques

Les opérations arithmétiques ne sont définies que si les opérandes sont des valeurs numériques, c'est-à-dire des feuilles étiquetées par des nombres. Si aucun de ces nombres n'est flottant, alors l'opération est considérée comme une opération exacte sur des nombres rationnels. Si l'un au moins des opérandes est flottant, alors l'autre est transformé en flottant, sauf s'il l'était déjà, et l'opération est considérée comme étant l'opération correspondante sur les nombres flottants.

Les opérations arithmétiques sont : (1) L'opération unaire “neutre”

a1 ! + a1

(2) L'opération unaire de changement de signe

a1 ! - a1

(3) L'opération binaire addition (a1, a2) ! a1+ a2

(4) L'opération binaire soustraction (a1, a2) ! a1- a2

(a1, a2) ! a1* a2

Afin d'alléger les écritures, la syntaxe de Prolog III permet d'écrire a1a2 à la place de a1*a2. A la condition, bien entendu, que cela ne change pas le sens de ce qui est écrit. Mais attention, il y a quelques pièges passablement vicieux : voyez le § 5.

(6) L'opération binaire division (a1, a2) ! a1/ a2

La division n'est définie que si a2 est différent de zéro.

Des termes corrects exprimant des opérations arithmétiques, ainsi que des fautes à ne pas commettre, sont montrés au § 5.

Opérations de construction d'arbres

Ces opérations permettent de construire des arbres non réduits à des feuilles. Nous avons :

(1) L'opération de construction d'arbre (a1, a2, … an) ! a1(a2, … an)

Pour que cette opération soit définie il faut que n " 2 et que a1 soit une feuille. Elle a pour résultat l'arbre dont l'étiquette est1 a

1 et dont les fils sont

a2, … an.

(2) L'opération de construction de tuple (a1, … an) ! < a1, … an>

1 En toute rigueur il faudrait dire «l'arbre dont l'étiquette est l'étiquette de a

1», mais comme nous l'avons dit, Prolog III ne distingue pas une feuille de son étiquette.

Elle est définie quelque soit le n-uplet (a1, … an), à la condition que n " 1 ; elle

a pour résultat le PIII-tuple dont a1, … an sont les éléments. On dit que n est

la longueur du tuple construit. L'égalité suivante découle de la définition même des tuples :

<a1, … an> = <>(a1, … an)

(3) L'opération binaire de construction générale d'arbre (a1, a2) ! a1[a2]

Cette opération n'est définie que si a1 est une feuille et a2 un tuple. Elle a pour résultat l'arbre qui a a1 pour étiquette et a2 pour suite de fils. Par définition, on a donc l'égalité :

a1[<b1, … bm>] = a1(b1, … bm)

(4) L'opération binaire de concaténation de tuples (a1, a2) ! a1 . a2

Elle n'est définie que si a1 et a2 sont tous les deux des tuples. Elle a pour résultat le tuple dont les éléments sont ceux de a1 suivis de ceux de a2. Par définition, on a donc l'égalité :

Les listes classiques

On peut aussi utiliser en Prolog III des listes classiques1, basées sur la notion de paire pointée, comme elles existent en Lisp ou dans d'autres Prolog. Dans la syntaxe d'Edimbourg2, ces listes s'écrivent de la manière suivante :

• liste vide :

[]

• liste ayant les éléments e1, e2, … en et terminée par [] :

[ e1, e2, … en ]

• liste ayant en tête les éléments e1, e2, … en et pour queue la liste q :

[ e1, e2, … en | q ]

Il faut bien comprendre que ceci n'est pas une opération de construction d'arbres spécifiquement prise en compte par Prolog III, mais uniquement un autre moyen syntaxique d'exprimer certains arbres : la paire pointée et le célèbre nil. A cet effet, on donne un statut d'identificateur au double signe [] et on code le doublet de base [e1|e2] par l'arbre [](e1,e2). Par conséquent, les expressions ci-dessus spécifient respectivement les arbres

[ ]

[](e1,[](e2,[](en,[])) )

[](e1,[](e2,[](en,q)))

Même si les tuples de Prolog III sont une amélioration indiscutable des listes classiques, toutes les règles prédéfinies de Prolog III qui sont héritées de Prolog II n'utilisent que ces dernières, afin de ne pas changer de compor- tement.

1 Nous disons ici “classiques” par opposition aux “nouvelles listes” que sont les tuples, mais dans la suite de cette documentation nous appellerons les listes classiques tout simplement des “listes”ou bien encore des "listes binaires".

2 Ces listes ne peuvent pas être exprimées en Prolog III avec la syntaxe qu'elles ont en Prolog II, c'est-à-dire « a1.a2. … . an», le point ayant ici un tout autre rôle syntaxique (il