Du « comment c’est fait ? » Au « à quoi ça sert ? »
Comment c’est fait ? Une table, ça a quatre pieds en métal de 80 cm de hauteur disposés aux coins d’un plateau en bois rectangulaire de 1m50 sur 70cm. C’est trop précis : pourquoi quatre pieds et pas trois ? Et pas assez précis : quelle est l’épaisseur du plateau ? Ça se réfère à des objets prédéfinis dont on suppose que l'on sait comment ils sont faits ( pied, plateau ).
Du « comment c’est fait ? » Au « à quoi ça sert ? »
A quoi ça sert ? Une table, ça permet à des gens de s’asseoir autour d’elle et de poser des objets sur elle; ça peut s’assembler avec une autre table pour former une table plus grande. Ce qui importe ce sont les fonctionnalités de la table par rapport à des usages définis par ailleurs ( s’asseoir, poser des objets ). La construction de la table peut se faire à partir d’objets élémentaires de même type ( assembler ).
De l’objet À sa structure
Sorte et Types (syntaxe) Une sorte est constituée d’objets d’un ou plusieurs types (ensembles). Pour chaque type, il existe une ou plusieurs façons de créer un objet de ce type (fonctions), éventuellement à partir d’autres objets : elles permettent de construire des objets de la sorte courante.
Les constantes booléennes BOOLEENS BOOLEENS – la sorte sort BOOLEENS is – le(s) types (s) BOOLEEN ; – le(s) constructeur(s) Vrai :=> BOOLEEN; Faux :=> BOOLEEN ; end BOOLEENS; Vrai et Faux sont des constantes (constructeurs sans arguments) BOOLEENnes, les seuls termes (objets syntaxiques) que l'on puisse engendrer.
Objets (?) Une sorte est constituée d’objets d’un ou plusieurs types (ensembles). Pour chaque type, il existe une ou plusieurs façons de créer un objet de ce type (fonctions),éventuellement à partir d’autres objets : elles permettent de construire des objets de la sorte courante.
Un opérateur interne BOOLEENS – la sorte sort BOOLEENS is – le(s) types (s) BOOLEEN ; – le(s) variable (s) BOOLEENS x : BOOLEEN; – le(s) constructeur(s) Vrai :=> BOOLEEN; Faux :=> BOOLEEN ; Non (x) => BOOLEEN; end BOOLEENS; x est un symbole générique pour désigner tout terme de type BOOLEEN. Non est un constructeur qui permet, pour tout terme x BOOLEEN, d'engendrer un nouveau terme Non (x). x peut donc désigner tout terme de type BOOLEEN : Vrai, Faux, Non (Vrai), Non (Non (Vrai)), … Non (… (Non (Vrai)) …),... Non (Faux), Non (Non (Faux)), … Non (… (Non (Faux)) …),...
Sorte et Types (syntaxe) L'ensemble des termes syntaxiquement engendrés par la grammaire régulière dont les règles sont données par les profils des constructeurs est en général infini (dénombrable). Tous ces termes sont syntaxiquement distincts, et jusque là, rien ne permet de leur donner d'autre sens que celui du terme qu'ils dénotent.
L’ensemble des termes d’un type donné peut être partitionné par des axiomes en sous-ensembles formés chacun de termes qui ont le même sens. Chaque classe de la partition peut être représentée par un terme n’utilisant que des constructeurs. Les axiomes permettent d’éliminer les extenseurs dans un terme pour trouver le terme représentatif de sa classe. Sorte et Types (sémantique)
La table de verité de la négation BOOLEENS – la sorte sort BOOLEENS is – le(s) types (s) BOOLEEN ; – le(s) variable (s) x : BOOLEEN; – le(s) constructeur(s) Vrai => BOOLEEN; Faux => BOOLEEN ; – le(s) extenseur(s) Non (x) => BOOLEEN isNon (Vrai) → Faux BOOLEENS | Non (Faux ) → Vrai; end BOOLEENS; On définit pour l'opérateur Non une règle de réécriture selon laquelle Non (Vrai) peut se réécrire Faux Non (Faux) peut se réécrire Vrai. En utilisant autant de fois que nécessaire cette réécriture, on peut éliminer Non de n'importe quel terme BOOLEEN. Cet opérateur devient un extenseur que l'on élimine par réécriture lorsqu'il est appliqué à l'un des constructeurs.
Les axiomes Un axiome est une règle de réécriture pour un terme qui est orientée ( de gauche à droite ), décroissante ( nombre de constructeurs auxquels les extenseurs s'appliquent ). Un terme est réductible s'il existe au moins une règle dont la partie gauche s' identifie à lui, réduit s'il ne contient plus d'extenseur.
L’ensemble des termes d’un type donné peut être partitionné par des axiomes en sous-ensembles formés chacun de termes qui ont le même sens. Chaque classe de la partition peut être représentée par un terme n’utilisant que des constructeurs. Les axiomes permettent d’éliminer les extenseurs dans un terme pour trouver le terme représentatif de sa classe. Sorte et Types (sémantique)
Constructeurs et Extenseurs Non (Vrai), Non (Non (Faux)), Non (Non (Non (Vrai))), sont des termes réductibles à Faux, Non (Faux), Non (Non (Vrai)), Non (Non (Non (Faux))), sont des termes réductibles à Vrai, Vrai et Faux sont les constructeurs : tout terme de type BOOLEEN peut être réduit à l’une de ces constantes. L’opérateur Non est un extenseur puisqu’il peut être éliminé de tout terme qui l’utilise.
Redondance Un système d'axiomes contient une redondance si une règle peut être remplacée par la composition d'autres règles. Pour le type BOOLEEN, la règle Non (Non (x)) → x serait redondante
Confluence Quelles que soient les règles de réécriture utilisées et l'ordre dans lequel on les utilise, le résultat est le même. Si on ajoute une opération Not (x) => BOOLEEN avec les règles Not (Not (x))→x, Not (Non (x))→x et Not (Vrai) → Vrai Alors Not (Not (Non (x))) se réécrit Non (x) ou Not (x). La confluence n'est pas assurée car Non (Vrai) → Faux alors que Not (Vrai) → Vrai
Complétude suffisante chaque opération dans la sorte est correctement définie pour toutes les entrées valides (ce n'est pas le cas de Not (Faux)) Tout terme peut être réduit de façon unique (éventuellement par plusieurs chemins).
Correction Pour que la spécification soit correcte et confluente il faut préférer à la règle : Not (Vrai) → Vrai Les deux règles Not (Vrai) → Faux et Not (Faux) → Vrai Elle comporterait néanmoins des redondances, à moins de supprimer Not (Not (x)) → x et Not (Non (x)) → x Le même comportement serait obtenu en définissant directement (opération de classe) Not (x) → Non (x)
Les problèmes majeurs... Contradiction : si on ajoute la règle Non (x) → x, on pourra inférer pour Non (Vrai) à la fois Vrai et Faux Divergence : si on ajoute la règle x → Non (Non (x)), on pourra inférer pour Vrai à la fois Non (Non ( … Non (Non (Vrai )) …)) sans que l'inférence termine
De l’objet À sa structure
Comment construire une sorte. Fixer la syntaxe –Identifier les différentes natures d’objets ( types ) nécessaires pour décrire la sorte. –Identifier les différentes méthodes applicables aux objets de la sorte et la façon de les appliquer ( profils ). Fixer la sémantique –Repérer les méthodes strictement nécessaires pour donner un sens à tout objet de la sorte (constructeurs). –Ecrire les axiomes qui permettent d’éliminer les autres méthodes (extenseurs) en appliquant chacune de ces méthodes à chacun des constructeurs ou à des termes génériques les représentant.
Les Booléens (syntaxe) BOOLEENS – la sorte sort BOOLEENS is – le(s) types (s) BOOLEEN ; – le(s) variable (s) B, G, D : BOOLEEN; – le(s) constructeur(s) Vrai => BOOLEEN; Faux => BOOLEEN ; – le(s) extenseur(s) Non (B) => BOOLEEN ; Ou (G, D) => BOOLEEN; Et (G, D) => BOOLEEN ; Excl (G, D) => BOOLEEN ; BOOLEENS Impl (G, D) => BOOLEEN ; end BOOLEENS; Des opérateurs (internes) binaires sont ajoutés à l'opérateur unaire : Ou, Et, Excl, Impl. Ils ne font qu'enrichir la syntaxe : Non (Et (OU (x, y), y)) est un terme BOOLEEN, On souhaite réécrire tout terme syntaxiquement en Vrai ou Faux Ces opérateurs seront donc traités comme des extenseurs.
Comment construire une sorte. Fixer la syntaxe –Identifier les différentes natures d’objets ( types ) nécessaires pour décrire la sorte. –Identifier les différentes méthodes applicables aux objets de la sorte et la façon de les appliquer ( profils ). Fixer la sémantique –Repérer les méthodes strictement nécessaires pour donner un sens à tout objet de la sorte (constructeurs). –Ecrire les axiomes qui permettent d’éliminer les autres méthodes (extenseurs) en appliquant chacun de ces extenseurs à chacun des constructeurs ou à des termes génériques les représentant.
Les Booléens (sémantique par table de vérité) Non (B) => BOOLEEN Non (B) => BOOLEEN is Non (Vrai) → Faux | Non (Faux) → Vrai; Et (G, D) => BOOLEEN is Et (Vrai, Vrai) → Vrai | Et (Vrai, Faux) → Faux | Et (Faux, Vrai) → Faux | Et (Faux, Faux) → Faux; Ou (G, D) => BOOLEEN is Ou (Vrai, Vrai) → Vrai | Ou (Vrai, Faux) → Vrai | Ou (Faux, Vrai) → Vrai | Ou (Faux, Faux) → Faux; Excl (G, D) => BOOLEEN is Excl (Vrai, Vrai) → Faux | Excl (Vrai, Faux) → Vrai | Excl (Faux, Vrai) → Vrai | Excl (Faux, Faux) → Faux; Impl (G, D) => BOOLEEN is Impl (Vrai, Vrai) → Vrai | Impl (Vrai, Faux) → Faux | Impl (Faux, Vrai) → Vrai | Impl (Faux, Faux) → Vrai; Non (Ou (Non (Vrai), Vrai)) → Non (Ou (Faux, Vrai)) Non (Ou (Faux, Vrai)) → Non (Vrai) Non (Vrai) → Faux
Comment construire une sorte. Fixer la syntaxe –Identifier les différentes natures d’objets ( types ) nécessaires pour décrire la sorte. –Identifier les différentes méthodes applicables aux objets de la sorte et la façon de les appliquer ( profils ). Fixer la sémantique –Repérer les méthodes strictement nécessaires pour donner un sens à tout objet de la sorte (constructeurs). –Ecrire les axiomes qui permettent d’éliminer les autres méthodes (extenseurs) en appliquant chacun de ces extenseurs à chacun des constructeurs ou à des termes génériques les représentant.
Les Booléens (sémantique simplifiée) Non (B) => BOOLEENNon (Vrai) → Faux | Non (Faux) → Vrai; Non (B) => BOOLEEN is Non (Vrai) → Faux | Non (Faux) → Vrai; ET (G, D) => BOOLEEN is ET (Faux, D) → Faux | ET (Faux, D) → Faux | ET (Vrai, D) → D; ET (Vrai, D) → D; OU (G,D) => BOOLEEN → NON(ET(NON(G),NON(D))); Excl (G, D) => BOOLEEN → ET(OU (G,D), NON(ET (G, D))); Impl (G, D) => BOOLEEN → OU (NON(G),D); Les règles définissant le ET sont obtenues par une fusion de règles élémentaires grâce à la généralisation de termes par des symboles de variables (G et D). Celles de Ou, Excl, Impl expriment des propriétés des BOOLEENs (règles de Morgan), à chaque opération n'est associée qu'une règle et celle ci opère directement sur des symboles de variables (sans constructeurs) : ce sont des opérations de classe.
Les Booléens (sémantique indéfinie) Non (B) => BOOLEENNon (Vrai) → Faux | Non (Faux) → Vrai; Non (B) => BOOLEEN is Non (Vrai) → Faux | Non (Faux) → Vrai; Et GD BOOLEEN NON(OU(NON(G),NON(D))); Et (G,D) => BOOLEEN → NON(OU(NON(G),NON(D))); OU (G,D) => BOOLEEN → NON(ET(NON(G),NON(D))); Excl (G, D) => BOOLEEN → ET(OU (G,D), NON(ET (G, D))); Impl (G, D) => BOOLEEN → OU (NON(G),D); Non ET et OU sont exprimés par les règles de Morgan : ces règles sont alors mutuellement récursives et ne terminent pas ; leur utilisation conduit à des termes de complexité croissante, en fonction du nombre d'extenseurs Non qu'elles utilisent : Non(ET(Non(Faux),Non(Vrai))) Non (Ou (Faux, Vrai)) → Non (Non(ET(Non(Faux),Non(Vrai)))) Non(ET(Non(Faux),Non(Vrai)))Non(ET(Vrai,Faux))) Non (Non(ET(Non(Faux),Non(Vrai)))) → Non (Non(ET(Vrai,Faux))) Non(ET(Vrai,Faux))) Non((Non(Vrai),Non(Faux))))) Non (Non(ET(Vrai,Faux))) → Non (Non (Non(Ou(Non(Vrai),Non(Faux))))) Non((Non(Vrai),Non(Faux)))))Non((Faux,Vrai)))) Non(Non(Non(Ou(Non(Vrai),Non(Faux)))))→Non(Non(Non(Ou(Faux,Vrai)))) Soit finalement Non((Faux,Vrai)))) Non (Ou (Faux, Vrai)) → Non(Non(Non(Ou(Faux,Vrai))))
De l’objet À sa structure
Considérations syntaxiques … Un certain nombre d’opérateurs peuvent être utilisés de façonInfixe,,,,,, …) (,,,,,,, …)préfixe (,,,,,, …) (,,,,,,, …)
sort BOOLEANS is BOOLEAN; -- Type Déclaré B,G,D : BOOLEAN ; -- Variables True,False=>BOOLEAN ; -- Constructeurs -- Extenseurs ; not_(B) BOOLEAN is not_(B)=> BOOLEAN is not False → True | not True → False not False → True | not True → False _and_(G D) BOOLEAN _and_(G, D) => BOOLEAN is False and D → False | False and D → False | True and D → D; True and D → D; _or_ (G,D) => BOOLEAN → not (not G and not D); not (not G and not D); _xor_(G, D)=>BOOLEAN → (G or D) and not (G and D); (G or D) and not (G and D); _>=_ (G, D) => BOOLEAN → not G or D ; _=_ (G, D)=> BOOLEAN→G >= D and D >= G; end BOOLEANS; Version Infixe des Booléens Les Booléens sont définis par une partition de l'ensemble des termes en deux sous ensembles. Grâce aux règles, les uns, se réécrivent en vrai, les autres en faux. L'égalité définie est alors, non pas celle des termes (au sens syntaxique), mais celle des classes d'équivalence auxquelles appartiennent les termes. Elle se confond avec l'équivalence logique.
Construction hiérarchique. Syntaxe et sémantique Syntaxe : Utiliser des sortes (ou des composants) prédéfinies dans la définition des termes de la sorte courante – Soit en important les sortes elles-mêmes, – Soit en indiquant les noms des types et les profils des opérateurs génériques utilisés. Sémantique (finale): Définir le sens des termes utilisant la sorte courante et dont la valeur est dans un type importé (observateurs).
Construction hiérarchique. Importation versus généricité En important une sorte, on importe TOUS les types et opérations qu'elle comporte, y compris ceux dont on ne fait pas usage, on importe la sémantique donnée par la spécification de la sorte importée. En définissant une sorte selon des paramètres (types et opérations) génériques, on utilise uniquement les types et opérations nécessaires à la sorte courante. on ne définit que la syntaxe de ces paramètres ; la sémantique de la sorte courante ne sera donc fixée que lorsque ces paramètres recevront des valeurs.
Considérations syntaxiques … with Les sortes importées sont introduites par le mot clef with; (with BOOLEANS;) Tout composant d'une sorte importée (type ou opération) doit être préfixé par le nom de la sorte dont il provient pour être utilisé dans la sorte courante; Tout composant d'une sorte importée (type ou opération) doit être préfixé par le nom de la sorte dont il provient pour être utilisé dans la sorte courante; (BOOLEANS.true) Cette contrainte est levée pour les sortes importées introduites par le mot clef use au risque de créer des ambiguités ; Cette contrainte est levée pour les sortes importées introduites par le mot clef use au risque de créer des ambiguités ;(use BOOLEANS;)
Considérations syntaxiques … Les types et opérations de sortes externes à la sorte courante qui n'appartiennent pas à des sortes importées sont déclarés (avec leur profil) derrière le mot clef generic. Generic BOOLEEN ; non_:BOOLEEN → BOOLEEN ; Sort GENERIQUE is... Seule leur syntaxe est ainsi fixée : c'est une instanciation par l'opérateur new qui permet d'associer à ces composants syntaxiques les sémantiques des sortes : With BOOLEANS ; Use BOOLEANS ; Sort GENERIQUE_BOOLEAN is new GENERIQUE (BOOLEEN => BOOLEAN, non_ => not_) ;
sort NATURELS is -- Types Déclarés NATUREL ; n, x, y : NATUREL -- Constructeurs zero => NATUREL; succ (n) => NATUREL; -- Extenseurs _+_(x, y) => NATUREL is → _+_(zero, y ) → y | → _+_(succ(x), y ) → succ (x+y) ; _*_(x, y) => NATUREL is → _*_(zero, y ) → zero | → _*_(succ(x), y ) → x*y + y ; _**_(x, y) => NATUREL is → _**_(x, zero) → succ (zero) | → _**_(x, succ(y)) → x**y * x ; end NATURELS; La sorte des naturels Dans cette première approche : Les termes NATURELs sont regroupés dans des classes d'équivalence qui sont les puissances successives de succ appliquées à zero. Les extenseurs * et ** se réécrivent eux-mêmes en des extenseurs (appliqués à un moindre nombre de constructeurs), L'égalité des termes (appartenant à une même classe d'équivalence) n'est pas encore énoncée.
Considérations syntaxiques … BOOLEANS est automatiquement importée par un with implicite BOOLEAN muni des opérations habituelles dont ses constantes True, False; ces constantes ne peuvent pas être redéfinies.La sorte BOOLEANS est automatiquement importée par un with implicite et avec elle le type BOOLEAN muni des opérations habituelles dont ses constantes True, False; ces constantes ne peuvent pas être redéfinies. Ce sont les expressions à valeur dans ce type que l’on appelle expressions booléennesCe sont les expressions à valeur dans ce type que l’on appelle expressions booléennes Les composants de cette sorte pourront être utilisés, grâce à un use implicite, sans que l'on précise qu'ils en proviennent.Les composants de cette sorte pourront être utilisés, grâce à un use implicite, sans que l'on précise qu'ils en proviennent.
sort NATURELS is Observateurs _ BOOLEAN is _<=_(zero, y ) → true | _<=_(succ (x), zero ) → false | _<=_(succ (x), succ (y)) → x <= y; _=_(x, y) => BOOLEAN → x <= y and y <= x; end NATURELS; La sorte des naturels (avec opérateurs relationnels) L'utilisation de la sorte BOOLEANS, implicitement importée, permet de définir deux opérateurs relationnels (<= et =), leur image est hors de la sorte : ce sont des observateurs. Ainsi on définit une relation d'ordre sur les NATURELs. Surtout on dispose d'une égalité ( =) qui exprime, par une expression booléenne, l'appartenance de deux termes à la même classe d'équivalence.
_-_(x,y)=>NATUREL :: y <= x is ? zero – succ (y) → ? | x – zero → x | →; succ (x) – succ (y) → x – y ; Opérateurs partiels Un opérateur peut ne pas être une application. son domaine de définition est alors restreint par une précondition (introduite par ::), cette précondition est une expression booléenne (y <= x), certaines règles de réécriture n'auront pas à être définies.
Axiomes conditionnels On souhaite parfois réécrire un terme selon les propriétés des arguments intervenant dans ce terme. _/_(x,y)=>NATUREL::succ(zero)<=y → if succ (x) <= y then zero else succ ((x – y) / y); _mod_(x,y)=>NATUREL::succ(zero)<=y → if succ (x) <= y then x else (x – y) mod y; On introduit pour cela une expression conditionnelle (if … then … else …) dans le méta-langage de définition des sortes. Le notion d'expression booléenne est donc nécessaire (comme premier argument de l'expression conditionnelle) dans ce méta- langage. Elle se conforme néanmoins à la théorie qui a été faite précédemment (sans expression conditionnelle) dans les BOOLEENS : elle en est un modèle.
Considérations syntaxiques … Les types INTEGER, NATURAL, POSITIVE, FLOAT, – munis de leurs opérations habituelles sont prédéfinis dans des sortes numériques. Ils bénéficient du même traitement que BOOLEAN
De l’objet À sa structure
Pairs et Impairs (une sorte multi-types) On définit les nombres pairs comme étant formés de zéro et des successeurs de nombres impairs et les nombres impairs comme étant les successeurs des nombres pairs. Une telle définition fait appel à la récursivité mutuelle entre deux types. Les naturels sont alors définis par une injection des pairs et des impairs dans un troisième type (muni de zero et de succ).
Generic NATUREL ; zero : NATUREL ; succ: NATUREL => NATUREL; Sort PARITY is EVEN, ODD, NAT ; x : EVEN ; y : ODD ; n : NAT; – Constructeurs none => EVEN ; succ (x)=> ODD ; succ (y)=> EVEN; inj (x) => NAT ; inj (y) => NAT; Pairs et Impairs (formellement spécifiés) – Extenseurs zero => NAT → inj (none) succ (n)=> NAT is succ (inj (x)) → inj (succ (x))| succ (inj (y)) → inj (succ (y)); – Observateurs val (n)=> NATUREL is val (inj (x)) → val (x) | val (inj (y)) → val (y); val (x)=> NATUREL is val (none) → zero | val (succ (y)) → succ (val (y)); val (y)=> NATUREL is val (succ (x)) → succ (val (x)); end PARITY; Deux des types de la sorte ( EVEN, ODD ) sont définis de façon mutuellement récursive et sont injectés dans un troisième ( NAT ) qui représente leur union. Si EVEN et ODD sont le produit de constructeurs, NAT en revanche relève d'extenseurs. Enfin les trois types sont mis chacun en relation avec un type NATUREL importé (muni de zero et succ), grâce à trois fonctions val spécialisées et elles-mêmes mutuellement récursives.
De l’objet À sa structure
Les comptes (définis par l’utilisateur) Gérer un compte c’est : L’ouvrir en faisant un dépôt initial (éventuellement nul), Le créditer en déposant un montant d’argent liquide, Le débiter en retirant un montant d’argent liquide, Le consulter pour connaître le montant disponible. Les dépôts et retraits se font en euros (sans centimes) et le découvert n’est pas autorisé.
-- BOOLEAN, NATURAL sont prédéfinis, munis de -- _+_, _-_ : NATURAL * NATURAL => NATURAL; -- _ BOOLEAN; sort accounts is -- Types Déclarés ACCOUNT ; -- Variables c : ACCOUNT ; m, n: NATURAL; Les comptes (formellement spécifiés) -- Constructeurs open (m) => ACCOUNT; -- Extenseurs put (c, n) => ACCOUNT is put(open (m), n) → open (m+n); get (c, n) => ACCOUNT :: n <=amount(c) is get (open (m), n) → open (m-n); -- Observateurs amount (c) => NATURAL is amount (open (m)) → m; end accounts; ) Dans cette première mouture, la seule information pertinente (le seul observateur) pour le compte est son solde ( amount). En conséquence, faire un dépôt ou retrait revient à ouvrir ( open ) un nouveau compte avec un montant initial égal au solde du montant initial de l'ancien compte et de l'opération réalisée. Dépôts et retraits ( put et ge t) sont donc des extenseurs de l'unique constructeur (open). Aucun sens n'a été donné à l'égalité de deux comptes.
Les comptes (avec statistiques sur les opérations) Gérer un compte c’est : L’ouvrir en faisant un dépôt initial (éventuellement nul), Le créditer en déposant un montant d’argent liquide, Le débiter en retirant un montant d’argent liquide, Le consulter pour connaître le montant disponible. Les dépôts et retraits se font en euros (sans centimes) et le découvert n’est pas autorisé. On veut connaître le solde après chacune des opérations effectuées précédemment.
-- NATURAL et BOOLEAN -- avec leurs opérations sont prédéfinis sort accounts is -- Types Déclarés ACCOUNT ; -- Variables c : ACCOUNT ; i, m, n: NATURAL; comment un extenseur devient constructeur Dans cette seconde mouture, On garde mémoire de l'historique par les observateurs (operations et amount), Substituer un nouveau compte à un compte ancien dont on modifie le solde ne suffit plus, Les extenseurs (put et get) doivent être traités comme constructeurs. La modification des observateurs change le statut des extenseurs. L'introduction de nouvelles opérations ne se fait pas selon une compatibilirté ascendante. -- Constructeurs open (m) => ACCOUNT; put (c, n) => ACCOUNT; get (c, n) => ACCOUNT :: n <=amount(c, operations (c)) ; -- Observateurs operations (c) => NATURAL is operations (open (m)) → 0 | operations (put (c, n)) → operations (c)+1 | operations (get (c, n)) → operations (c)+1; amount (c, i) => NATURAL :: i <=operations (c) is amount (open (m), i) → m | amount (put (c, n), i) → if operations (c) + un <= i then amount (c, i-un)+m else amount (c, i) | amount (get (c, n), i) → if operations (c) + un <= i then amount (c, i-un)-m else amount (c, i); end accounts;
De l’objet À sa structure
-- BOOLEAN est prédéfini, muni de -- false, true: => BOOLEAN; -- not_: BOOLEAN => BOOLEAN; generic OBJET ; – ce que l'on met dans la pile sort PILES is -- Types Déclarés PILE; -- Variables p : PILE ; x : OBJET; Quelques Standards : la Pile -- Constructeurs creer => PILE; empiler (p, x)=> PILE; -- Extenseurs depiler (p)=> PILE :: not vide (p) is depiler (empiler (p, x)) → p; -- Observateurs sommet (p) => OBJET :: not vide (p) is sommet (empiler (p, x)) → x; vide (p) => BOOLEAN is vide (creer) → true | vide (empiler (p, x)) → false; end PILES; Dernier entré, premier sorti (LIFO). Indispensable pour gérer les calculs récursifs.
-- BOOLEAN est prédéfini, muni de -- false, true: => BOOLEAN; -- not_: BOOLEAN => BOOLEAN; generic OBJET ; – ce que l'on met dans la file sort FILES is -- Types Déclarés FILE; -- Variables f : FILE ; x : OBJET; Quelques Standards : la File -- Constructeurs creer => FILE; enfiler (f, x)=> FILE; -- Extenseurs defiler (f)=> FILE :: not vide (f) is defiler (enfiler (f, x)) → if vide (f) then f else enfiler(defiler(f), x) ; -- Observateurs tête (f) => OBJET :: not vide (f) is tête (enfiler (f, x)) → if vide (f) then x else tête (f) ; vide (f) => BOOLEAN is vide (creer) → true | vide (enfiler (f, x)) → false; end FILES; Premier entré, premier sorti (LIFO). adapté pour gérer les files d'attentes (buffers, imprimantes).
-- BOOLEAN est prédéfini, muni de -- false, true: => BOOLEAN; -- not_: BOOLEAN => BOOLEAN; generic OBJET ; – ce que l'on met dans la file sort FILES is -- Types Déclarés FILE; -- Variables f : FILE ; x : OBJET; Quelques Standards : la File -- Constructeurs creer => FILE; enfiler (f, x)=> FILE; -- Extenseurs defiler (f)=> FILE :: not vide (f) is defiler (enfiler (f, x)) → if vide (f) then f else enfiler(defiler(f), x) ; -- Observateurs tête (f) => OBJET :: not vide (f) is tête (enfiler (f, x)) → if vide (f) then x else tête (f) ; vide (f) => BOOLEAN is vide (creer) → true | vide (enfiler (f, x)) → false; end FILES; Premier entré, premier sorti (LIFO). adapté pour gérer les files d'attentes (buffers, imprimantes).
-- BOOLEAN et NATURALprédéfinis, -- munis de leurs opérations generic OBJET ; – ce que l'on met en tas _=_: OBJET * OBJET => BOOLEAN; sort TASA is -- Types Déclarés TAS; -- Variables f : TAS ; x, y : OBJET; i : Natural ; -- Constructeurs creer => TAS; mettre (f, x)=> TAS :: not dans (f, x); Quelques Standards : le Tas à l'ancienneté -- Extenseurs retirer (f, x)=> TAS :: dans (f, x) is retirer (mettre (f, y) x) → if x=y then f else mettre (retirer (f, x) y); -- Observateurs dans (f, x)=> BOOLEAN is dans (creer, x) → false dans (mettre (f, y), x) → if x=y then true else dans (f, x); taille (f) => NATURAL is taille (creer) → 0 | taille (mettre (f, x))→ taille (f, x) + 1; ieme (f, i)=> OBJET :: 1 <= i and i <= taille (f) is ieme (mettre (f, y), i) → if taille(f)<i then y else ieme (f, i); end TASS; appartenance ; unicité de l 'objet dans le tas ; choix de l'élément retiré. fondé sur l'égalité des objets.
-- BOOLEAN et NATURAL prédéfinis, -- munis de leurs opérations generic OBJET ; – ce que l'on met en tas _ BOOLEAN; sort TAS0S is -- Types Déclarés TASO; -- Variables f : TASO ; x, y : OBJET; i : Natural ; -- Constructeurs creer => TASO; mettre (f, x)=> TASO :: not dans (f, x); -- Extenseurs retirer (f, x)=> TASO :: dans (f, x) is retirer (mettre (f, y) x) → if x=y then f else mettre (retirer (f, x) y); Quelques Standards : le Tas ordonné -- Observateurs dans (f, x)=> BOOLEAN is dans (creer, x) → false dans (mettre (f, y), x) → if x<=y and y <= x then true else dans (f, x); taille (f) => Natural is taille (creer) → 0 | taille (mettre (f, x))→ taille (f, x) + 1; ieme (f, i)=> OBJET :: 1 <= i and i <= taille (f) is ieme (mettre (f, x), i) → if i <= taille (f) then if ieme (f, i) <=x then ieme (f, i) else if i = 1 then x else if ieme (f, i - 1) <= x then x else ieme (f, i - 1) else if i = 1 then x else if ieme_inscrit (f, i - 1) <= x then x else ieme (f, i - 1) end TASOS; fondé sur l'une relation d'ordre total entre les objets.
-- BOOLEAN prédéfinis, -- munis de leurs opérations generic OBJET ; – ce que l'on met en tas _=_: OBJET * OBJET => BOOLEAN; sort ENSS is -- Types Déclarés ENS; -- Variables f, g : ENS; x, y : OBJET; -- Constructeurs creer => ENS; mettre (f, x)=> ENS; -- Extenseurs retirer (f, x)=> ENS :: dans (f, x) is retirer (mettre (f, y) x) → if x=y then if dans (f, x) then retirer (f, x) else f else mettre (retirer (f, x) y); autres (f) => ENS :: not vide (f) → retirer (f, un (x)) Quelques Standards : l'ensemble (sous-spécifié) -- Observateurs un (f) => Objet !! dans (f, un (f)) ; – sous-spécifié dans (f, x)=> BOOLEAN is dans (creer, x) → false dans (mettre (f, y), x) → if x=y then true else dans (f, x); vide (f)=> BOOLEAN is vide (creer) → true vide (mettre (f, x)) true else dans (f, x); end ENSS; vide l'opération un n'est pas axiomatisée. elle est seulement soumise à post-condition !! l'implémentation fixera le choix de l'objet.
-- BOOLEAN et NATURAL prédéfinis, -- munis de leurs opérations generic OBJET ; – ce que l'on met en arbre _=_: OBJET * OBJET => BOOLEAN; sort ABS is -- Types Déclarés AB; -- Variables a, g, d : AB; x, y : OBJET; -- Constructeurs creer => AB | enraciner (x, g, d)=> AB; -- Extenseurs gauche(a)=> AB :: not vide (a) is gauche (enraciner (x, g, d)) → g; droite(a)=> AB :: not vide (a) is droite (enraciner (x, g, d)) → d; Quelques Standards : l'arbre binaire -- Observateurs racine (a)=> OBJET :: not vide (a) is racine (enraciner (x, g, d)) → x; vide (a)=> BOOLEAN is vide (creer) → true | vide (enraciner (x, g, d)) → false; dans (a, y)=> BOOLEAN is dans (creer, y) → false | dans (enraciner (x, g, d), y) → x=y OR dans (g, y) OR dans (d, y) end ABS; ce n'est plus une structure linéaire, son fonctionnement est proche de celui de la pile (traversable).
-- BOOLEAN prédéfinis, -- munis de leurs opérations generic OBJET ; – ce que l'on met en arbre _ BOOLEAN; sort ABOS is -- Types Déclarés ABO; -- Variables a, g, d : ABO ; x, y : OBJET; -- Constructeurs creer => ABO ; enraciner (x, g, d)=> ABO :: g <= x and x <= d; -- Extenseurs gauche(a)=> AB :: not vide (a) is gauche (enraciner (x, g, d)) → g; droite(a)=> AB :: not vide (a) is droite (enraciner (x, g, d)) → d; Quelques Standards : l'arbre binaire ordonné -- Observateurs a BOOLEAN is creer <= y → true | enraciner (x, g, d) <= y → if vide (d) then x <= y else d <= y ; y BOOLEAN is y <= creer → true | y <= enraciner (x, g, d)→ if vide (g) then y <= x else y <= g ; racine (a)=> OBJET :: not vide (a) is racine (enraciner (x, g, d)) → x; vide (a)=> BOOLEAN is vide(creer)→true | vide (enraciner (x, g, d))→false; dans (a, y)=> BOOLEAN is dans (creer, y) → false | dans (enraciner (x, g, d), y) → if x<=y then if y <=x then true else dans (d, y) else dans (g, y) end ABOS; fondé sur un ordre total sur les objets, il peut accélérer la recherche (équilibre ?).
-- BOOLEAN prédéfinis, -- munis de leurs opérations generic OBJET; – ce que l'on met en table INDEX; – ce qui organise la table _=_: INDEX * INDEX=> BOOLEAN; sort TABS is -- Types Déclarés TAB; -- Variables t : TAB; x : OBJET; i, j : INDEX; -- Constructeurs creer => TAB; placer (t, i, x)=> TAB :: NOT defini (t, i); Quelques Standards : la table -- extenseurs remplacer(t, i, x)=> OBJET :: defini (t, i) is remplacer(placer (t, j, x), i, y) → if i = j then y else placer(remplacer (t, i, y), j, x); -- observateurs contenu (t, i)=> OBJET :: defini (t, i) is contenu (placer (t, j, x), i) → if i = j then x else contenu (t, i); defini (t, i)=> BOOLEAN is defini (creer, i) → false | defini (placer (t, i, x), j) → if i = j then true else defini (t, j); end TABS; accès « direct » par un index, structure non contrainte.
-- BOOLEAN, NATURAL prédéfinis, -- munis de leurs opérations generic OBJET; – ce que l'on met en table DEFAUT : OBJET ; LONGUEUR : NATURAL; sort TABLEAUX is -- Types Déclarés TABLEAU; -- Variables t : TABLEAU; x : OBJET; i, j : NATURAL; -- Constructeurs creer => TABLEAU; placer (t, i, x)=> TABLEAU :: 1<=i and i <= LONGUEUR; Quelques Standards : le tableau -- Observateurs contenu (t, i)=> OBJET :: 1<=i and i <= LONGUEUR is contenu (creer, i) → DEFAUT | contenu (placer (t, j, x), i) → if i = j then x else contenu (t, i); end TABLEAUX; l'index est énuméré borné, structure contrainte.
-- BOOLEAN prédéfinis, -- munis de leurs opérations generic OBJET; – ce que l'on met en table sort LISTES is -- Types Déclarés LISTE; -- Variables l : LISTE; x : OBJET; -- Constructeurs creer => LISTE; inserer (l, x)=> LISTE ; inserer_avant (l, x)=> LISTE ; -- Extenseurs avancer(l)=> LISTE :: not en_queue (l) → inserer_avant (retirer(l),fenetre(l)); reculer(l) => LISTE :: not sur_tete (l)→ Inserer (retirer_avant(l),fenetre_avant(l)); Quelques Standards : la liste ? -- Observateurs sur_tete(l) => BOOLEAN is sur_tete(creer)→true | sur_tete(inserer (l, x))→sur_tete(l) | sur_tete(inserer_avant (l, x))→false; en_queue(l) => BOOLEAN is en_queue(creer)→true | en_queue(inserer (l, x))→false | en_queue(inserer_avant (l, x))→en_queue(l); fenetre(l) => OBJET :: not en_queue (l) is fenetre(inserer (l, x))→x | fenetre(inserer_avant (l, x))→fenetre(l); fenetre_avant(l)=> OBJET :: not sur_tete(l) is fenetre_avant(inserer (l, x))→fenetre_Avant(l) | fenetre_avant(inserer_avant (l, x))→x; end LISTES; Pour définir la sémantique de la liste on est amené à introduire deux opérations complémentaires privées : inserer_avant, fenetre_avant. |
De l’objet À sa structure