Types existentiels

Transcription

Types existentiels
Types abstraits de données
Manipulation de domaines complexes.
La manipulation est indépendante de la représentation
particulière du domaine.
On se donne :
Un nom pour domaine abstrait
Des opérations de construction d'une représentation concrète
vers le domaine abstrait
Des opérations de test pour les diérents constructions.
Des opérations d'accès d'un objet abstrait vers les
composantes d'une représentation concrète.
Types existentiels
1
Exemple : exemplaire
Exemple : jour
Domaine :
exemplaire
Domaine :
jour
(jours vus comme des entiers de 1 à 31)
Opérations de construction :
Opérations de construction :
cons_livre : livre → exemplaire
cons_jour : {x : entier | 1 ≤ x ≤ 31} → jour
cons_video : video → exemplaire
Opérations de construction étendue :
Opérations de test :
entier_to_jour : entier → jour
est_livre,est_video : exemplaire → bool
Opérations d'accès :
Opérations d'accès :
numéro_jour : jour → {x : entier | 1 ≤ x ≤ 31}
ex_livre : {x : exemplaire | est_livre(x)} → livre
ex_video : {x : exemplaire | est_video(x)} → video
2
3
Exemple : Les cartes de couleur
Exemple : argent
Domaine :
Domaine :
couleur
argent
Constantes :
Opérations de construction :
pique,coeur,carreau,trèfle : couleur
francs : entier → argent
euros : entier → argent
Opérations de test :
Domaine :
est_francs,est_euros : argent → bool
figure
Opérations d'accès :
Constantes :
val_argent : argent → entier
as,roi,dame,valet, dix,neuf,huit,sept : figure
4
5
Domaine :
main
Domaine :
Opérations de construction :
carte
cons_main : {~n ∈ carte5 | Diff(~n)} → main
Opérations de construction :
Opérations de construction étendue :
cons_carte : couleur × figure → carte
carte5 _to_main : carte5 → main
Opérations d'accès :
Opérations d'accès :
figure_carte : carte → figure
carte1 : main → carte
..
.
couleur_carte : carte → couleur
carte5 : main → carte
6
7
Domaine :
carte_tarot
Constantes :
Opérations d'accès :
excuse : carte_tarot
couleur_de_tarot : {x : carte_tarot | est_carte_simple(x)}
→ couleur
Opérations de construction :
figure_de_tarot : {x : carte_tarot | est_carte_simple(x)}
cons_tarot_simple : carte → carte_tarot
→ figure
cons_atout : {n : entier | 1 ≤ n ≤ 21} → carte_tarot
atout_de_tarot : {x : carte_tarot | est_atout(x)} →
Opérations de construction étendue :
{n : entier | 1 ≤ n ≤ 21}
entier_to_carte_tarot : entier → carte_tarot
Opérations de test :
est_carte_simple,est_atout : carte_tarot → bool
8
9
Forme générale d'un TDA
Opérations de construction étendue :
Domaine :
dom1 _to_dom : d1 → dom
..
.
dom
Constantes :
domm _to_dom : dm → dom
c1 , . . . , cn : dom
Opérations de test :
Opérations de construction :
est_c1 , . . . , est_cn : dom → bool
..
.
cons_dom1 : {x : d1 | P1 (x)} → dom
..
.
est_op1 , . . . , est_opm : dom → bool
cons_domm : {x : dm | Pm (x)} → dom
10
11
Quelques variantes
On peut omettre ou rajouter quelques items selon les cas :
Si la propriété Pi (x) est toujours true, alors on l'écrit pas.
Si le domaine est construit à partir d'une seule constante ou
d'une seule opération de construction, alors inutile d'écrire
l'opération de test car elle est équivalente à est(x) = true.
Si le domaine est construit à partir de m opérations de
construction, alors m − 1 opérations de test susent.
Si un domaine di est un produit cartésien a1 × . . . × ak , alors on
peut remplacer l'opération d'accès
Opérations d'accès :
acces1 : {x : dom | est_op1 (x)} → {x : d1 | P1 (x)}
..
.
accesm : {x : dom | est_opm (x)} → {x : dm | Pm (x)}
Autres opérations :
..
.
accesi : {x : dom | est_opi (x)} → {x : di | Pi (x)}
par k opérations de la forme
12
13
Le Tarot en OCAML
(* type couleur *)
#type couleur = Pique | Coeur | Carreau | Trefle;;
accesi1 : {x : dom | est_opi (x)} →
..
.
{y : a1 | y = proj1 (x) et x : di et Pi (x)}
(* Constructeurs pour les constantes de couleur *)
accesik : {x : dom | est_opi (x)} →
{y : ak | y = projk (x) et x : di et Pi (x)}
14
#let
#let
#let
#let
pique
coeur
carreau
trefle
=
=
=
=
Pique;;
Coeur;;
Carreau;;
Trefle;;
15
#let huit
#let sept
(* type figure *)
#type figure =
As | Roi | Dame | Cavalier | Valet | Dix | Neuf | Huit | Sept;;
(* Constructeurs pour les constantes de figure *)
#let
#let
#let
#let
#let
#let
#let
=Huit;;
=Sept;;
(* type carte *)
#type carte = Carte of figure * couleur;;
as
=As;;
roi
=Roi;;
dame
=Dame;;
cavalier=Cavalier;;
valet =Valet;;
dix
=Dix;;
neuf
=Neuf;;
(* opération de construction du type carte *)
#let cons_carte(f,c) = Carte(f,c);;
16
(* opérations d'accès du type carte *)
#let figure_carte(e) = match e with Carte(f,c)->f;;
#let couleur_carte(e) = match e with Carte(f,c)->c;;
17
(* opérations de construction du type carte_tarot *)
#let int_to_carte_tarot (n) =
if 1 <= n & n <= 21
then cons_atout (n)
else failwith"numéro d'atout invalide";;
(* type carte_tarot *)
#type carte_tarot =
Excuse | Simple of carte | Atout of int;;
(* opérations de construction étendue du type carte_tarot *)
(* opérations de test du type carte_tarot *)
#let excuse
= Excuse;;
#let cons_tarot_simple(c) = Simple(c);;
#let cons_atout (n)
= Atout(n);;
#let est_carte_simple (c) =
match c with Simple(_) -> true | _ -> false;;
18
19
#let est_atout (c)
=
match c with Atout(_) -> true | _ -> false;;
(* opérations d'accès du
#let figure_de_tarot (e) =
match e with
Simple(Carte(f,_)) -> f
| _
-> failwith "Pas une carte simple";;
type carte_tarot *)
#let couleur_de_tarot (e) =
match e with
Simple(Carte(_,c)) -> c
| _
-> failwith "Pas une carte simple";;
#let atout_de_tarot (e) =
match e with
Atout(x) -> x
| _
-> failwith "Pas un atout";;
20
Les prols de symboles de la signature
pique:
coeur:
carreau:
trefle:
as:
roi:
dame:
cavalier:
valet:
dix:
neuf:
huit:
->
->
->
->
->
->
->
->
->
->
->
->
21
sept:
cons_carte:
figure * couleur
figure_carte:
carte
couleur_carte:
carte
excuse:
cons_tarot_simple: carte
cons_atout:
int
int_to_carte_tarot:int
est_carte_simple: carte_tarot
est_atout:
carte_tarot
figure_de_tarot: carte_tarot
couleur_de_tarot: carte_tarot
atout_de_tarot:
carte_tarot
couleur
couleur
couleur
couleur
figure
figure
figure
figure
figure
figure
figure
figure
22
->
->
->
->
->
->
->
->
->
->
->
->
->
figure
carte = <fun>
figure = <fun>
couleur = <fun>
carte_tarot
carte_tarot = <fun>
carte_tarot = <fun>
carte_tarot = <fun>
bool = <fun>
bool = <fun>
figure = <fun>
couleur = <fun>
int = <fun>
23
Codage abstrait
Codage d'autres opérations d'un TDA
Abstrait : on utilise uniquement les opérations abstraites dénies
dans le TDA.
Concret : on utilise les primitives du langage de programmation
associées au domaines concrets utilisés dans le TDA.
#let points (c) =
if c = excuse
then 4.5
else if est_carte_simple (c)
then let f = figure_de_tarot(c) in
if f = roi
then 4.5
else if f = dame
then 3.5
else if f = cavalier
then 2.5
else if f = valet
24
25
Codage concret
#let points(c) = match c with
Excuse
-> 4.5
| Simple(Carte(f,_)) -> (match f with
Roi
->
| Dame
->
| Cavalier ->
| Valet
->
| _
->
| Atout(1)
-> 4.5
| Atout(21)
-> 4.5
| _
-> 0.5;;
val points : carte_tarot -> float = <fun>
then 1.5
else 0.5
else let n = atout_de_tarot(c) in
if n=1 or n=21
then 4.5
else 0.5;;
val points : carte_tarot -> float = <fun>
26
4.5
3.5
2.5
1.5
0.5)
27
Types existentiels
Exemples simples
Types : A ::= . . . | ∃α.A
Expressions : M ::= . . . | pack M with A as ∃α.A
p1 = pack 0 with int as ∃α.α
p2 = pack (0, λx : int.x + 0) with int as ∃α.(α × (α → α))
Règle de typage pour l'introduction de ∃α.A :
p3 = pack (0, λx : int.x + 0) with int as ∃α.(α × (α → int))
Γ ` M : A{α/B}
p4 = pack (true, λx : bool.1) with bool as ∃α.(α × (α → int))
Γ ` pack M with B as ∃α.A : ∃α.A
p5 = pack (0, λx : int.x + 0) with int as ∃α.(int × (int → int))
Le terme M donne une implémentation d'un TDA ayant signature
A. Le type B utilisé dans l'implémentation du TDA est caché si α
a des occurrences libres dans le type A.
p1 ne sert à rien, p2 et p3 ont la même implémentation mais
diérente signature, p3 et p4 ont la même signature mais diérente
implémentation, p5 ne cache rien.
28
29
On peut aussi écrire :
let a = 0; ;
let f = λx : int.x + 0; ;
let p = pack (a, f ) with int as ∃α.(a : α × (f : α → α)); ;
Exemple : un TDA
Ou bien
let z = {a = 0; f = λx : int.x + 0}; ;
let p = pack z with int as ∃α.(a : α × (f : α → α)); ;
z.a et z.f sont les composantes de z .
30
31
Domaine :
Exemple : une première implémentation
type_pile
#type pile = intlist;;
Constantes :
#let pile_vide = [];;
val pile_vide : intlist
pile_vide : type_pile
Opération de construction :
cons_pile : entier × type_pile → type_pile
#let cons_pile(a,p) = a::p;;
val cons_pile : int * intlist -> intlist = <fun>
Opération de test :
est_pile_nv : type_pile → bool
Opérations d'accès
premier_pile : {x : type_pile | est_pile_nv(x)} → entier
reste_pile : {x : type_pile | est_pile_nv(x)} → type_pile
#let est_pile_nv(p) =
match p with a::l -> true | _ -> false;;
val est_pile_nv : intlist -> bool = <fun>
32
33
type_pile =
α × (int × α → α) × (α → bool) × (α → int) × (α → α)
M = (pile_vide, cons_pile, est_pile_nv,
#let premier_pile(p) = match p with a::l -> a;;
val premier_pile : intlist -> int = <fun>
premier_pile, reste_pile)
type_pile{α/intlist} = intlist × (int × intlist → intlist)×
#let reste_pile(p) = match p with a::l -> l;;
val reste_pile : intlist -> intlist = <fun>
(intlist → bool) × (intlist → int) × (intlist → intlist)
Γ ` M : type_pile{α/intlist}
Γ ` pack M with intlist as ∃α.type_ pile : ∃α.type_pile
34
35
Exemple : une autre implémentation
# let reste_pile_nv(p) = p.reste;;
val reste_pile_nv : pile_nv -> ma_pile = <fun>
#type pile_nv = {tete:int; reste:ma_pile} and
ma_pile = Pile_Vide | P of pile_nv;;
# let pile_vide =Pile_Vide;;
val pile_vide : ma_pile = Pile_Vide
type pile_nv = { tete : int; reste : ma_pile; } and
ma_pile = Pile_Vide | P of pile_nv
# let cons_pile(a,p) = P(cons_pile_nv(a,p));;
val cons_pile : int * ma_pile -> ma_pile = <fun>
# let cons_pile_nv(t,r) = { tete=t ; reste = r};;
val cons_pile_nv : int * ma_pile -> pile_nv = <fun>
# let est_pile_nv(p) =
match p with Pile_Vide -> false | _ -> true ;;
val est_pile_nv : ma_pile -> bool = <fun>
# let tete_pile_nv(p) = p.tete;;
val tete_pile_nv : pile_nv -> int = <fun>
36
37
type_pile =
# let premier_pile(p) = match p with
Pile_Vide -> failwith"Pile Vide"
| P(x)
-> x.tete;;
val premier_pile : ma_pile -> int = <fun>
α × (int × α → α) × (α → bool) × (α → int) × (α → α)
M = (pile_vide, cons_pile, est_pile_nv,
premier_pile, reste_pile)
type_pile{α/ma_pile} = ma_pile × (int × ma_pile → ma_pile)×
# let reste_pile(p) = match p with
Pile_Vide -> failwith"Pile Vide"
| P(x) -> x.reste;;
val reste_pile : ma_pile -> ma_pile = <fun>
(ma_pile → bool) × (ma_pile → int) × (ma_pile → ma_pile
Γ ` M : type_pile{α/ma_pile}
Γ ` pack M with ma_pile as ∃α.type_ pile : ∃α.type_pile
38
39
Règle de typage pour l'élimination de ∃α.A :
Γ ` M : ∃α.A
Exemples simples
Γ, z : A ` N : C
Soit p une implémentation du type ∃α.(a : α, f : α → int)
Γ ` unpack M as β with z : A in N : C
unpack p as β with z : A in z.f (z.a) + 2
où la variable β n'est pas dans C
unpack p as β with z : A in z.a + 2
On ouvre l'implémentation M dans le programme N en lui
donnant un nom z et en supposant que le type caché est β .
(unpack p as β with z : A in z.a) + 2
40
Sémantique
Si p = pack M with B as ∃α.A, alors
unpack p as β with y : A in N se réduit dans
N {y/M }{α/β} qui se comporte comme
let y : A = M in N
42
(mal typé)
(mal typé)
41

Documents pareils