variants polymorphes et sous-typage

publicité
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
Variants polymorphes
Exemples (somme1.ml)
Programmation Fonctionnelle Avancée
8 : Utilisation avancée du system de typage :
variants polymorphes et sous-typage
Ralf Treinen
type
num = Z e r o
l e t re c
add =
|
( Zero , n )
|
( S n , m)
S
of
num ; ;
function
−>
−>
Université Paris Diderot
UFR Informatique
Institut de Recherche en Informatique Fondamentale
let
two = S
[email protected]
add
( two , two ) ; ;
(
|
S
n
S
( add
( n ,m ) ) ; ;
( Zero ) ) ; ;
24 novembre 2016
c
Roberto Di Cosmo et Ralf Treinen
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
Variants polymorphes
Caractéristiques des types sommes
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
Variants polymorphes
Exemples (somme2.ml)
type t 1
let x =
type t 2
I Il faut déclarer le type avec ses constructeurs avant de les
utiliser.
I Un constructeur appartient à un seul type somme ; si on
B;;
let
déclare plusieurs types somme ayant le même constructeur,
seule la dernière déclaration est visible (même si OCaml fait un
eort pour desambiguer les constructeurs dans certains cas).
(∗
= A
= B
now
isB2 =
|
B
|
C
|
B;;
|
C;;
B;;
of
type
function
−> t r u e
−> f a l s e
;;
let
|
A
|
B
−>
−>
;;
isB1
function
false
true
isB1 =
x ;;
t2
∗)
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
Variants polymorphes
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
Variants polymorphes
Variants polymorphes, syntaxe
Exemples (variant1.ml)
I Les variants polymorphes sont d'autres constructeurs qui
peuvent être utilisés sans avoir été déclarés préalablement dans
let
x =
`A ; ;
un type.
I Syntaxiquement, on les fait précéder d'une apostrophe à
l'envers `
`A
true
`B
4;;
;;
I Un variant polymorphe :
I peut appartenir à plusieurs types
I
I
peut être utilisé avec plusieurs types d'arguments
donne lieu à des types qui sont des listes de variants, avec
possiblement des bornes supérieures (<) et/ou inférieures (>),
et une relation de sous-typage qui est réalisée à travers le
polymorphisme (d'où le nom).
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
Variants polymorphes
Variants polymorphes : borne inférieure
I le > signie : un type qui contient au moins les
constructeurs suivants ; c'est une borne inférieure qui
apparaît quand on produit une valeur dont on sait qu'elle peut
contenir au moins les constructeurs qui apparaissent dans le
type
( `A,
let
`B
l
=
3);;
[ `A
types d'arguments diérents
( `B
4)];;
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
Variants polymorphes
Exemples (variant2.ml)
let
f =
function
|
`A
|
`A 3
−>
−>
[ `A;
`A
3];;
( `A,
`A
5);;
I la barre verticale signie ou .
I Un type ne peut pas contenir le même constructeur avec des
;
1
2;;
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
Variants polymorphes
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
Variants polymorphes
Interprétation des bornes inférieures
Exemples (variant3.ml)
I Une borne inférieure (ou supérieure) est un type polymorphe
(∗
avec une contrainte.
I [> `A | ` B] est à lire comme
'a
où
borne
let
`A ∈ 'a ∧ `B ∈ 'a
I le type [> `A | ` B] est une instance, à la fois de [> `A ] (et
f =
|
`B x
|
`A x
superieure
∗)
function
−>
−>
x
x
;;
aussi de [> `B]) car
`A ∈ 'a ∧ `B ∈ 'a
implique
`A ∈ 'a
(∗
I C'est une des raisons pourquoi l'inférence de type utilise la
résolution de contraintes.
I Les variantes polymorphes donnent lieu à une notion de
quelle
let
est
switch =
|
`A
|
`B
−>
−>
le
type
de
cette
fonction
?
∗)
function
`B
`A
;;
sous-typage (voir la suite).
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
Variants polymorphes
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
Variants polymorphes
Bornes supérieures
Exemples (variant4.ml)
I Le < signie : un type qui peut contenir au plus les
constructeurs suivants ; c'est une borne supérieure qui
apparaît quand on consomme une valeur dont on sait traiter
seulement les constructeurs qui apparaissent dans le type.
I [< `A | ` B] est à lire comme
'a
où
∀ x ∈ 'a : x = `A ∨ x = `B
let
f =
function
`S
a
−>
1
|
`Z
−>
2;;
let
g =
function
`S _
−>
4
|
_
−>
5;;
let
h =
function
`S _
−>
4
|
x
−>
f
x ;;
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
Variants polymorphes
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
Variants polymorphes
Le bornes supérieures et inférieures ensemble
On peut nommer les types
I On peut utiliser les types des variants dans une dénition de
I f a un
<
parce que il n'accepte que ces deux cas.
type.
Un ltrage par motif fermé donne une borne supérieure.
I g a un
>
I On ne peut pas utiliser les bornes directement dans les
parce que grâce au cas _−> 5 il accepte tout type
dénitions : un type avec borne, aussi appelé type ouvert
qui peut contenir au moins ` S.
représente un ensemble de types (tous les types compris entre
Un ltrage par motif ouvert donne une borne inférieure.
les bornes), et pas un seul type ; on ne peut donc pas les
I h a un
>
nommer.
comme g, mais le x doit être acceptable pour f , d'où
la même borne supérieure
<
que pour f .
I Par contre, on peut utiliser ces types ouverts dans des
contraintes de type.
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
Variants polymorphes
Variants polymorphes
Exemples (variant5.ml)
type
type
let
let
let
let
let
good =
[ `A
b a d = [>
f =
Exemples (variant6.ml)
|
`A
:
|
bool
function
gc = ( g
fcc = ( f
:
[<
:
(∗
of i n t ] ; ;
` B of i n t ] ; ;
`B
f u n c t i o n t r u e −>
fc = ( f
g =
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
−>
`A
`A ]
bool
[>
`A
|
f a l s e −>
`A
|
`B
−> 1 |
−> i n t
−>
[<
let
let
−>
`B
|
2;;
);;
`A
|
`C ] )
`B ; ;
(∗
let
let
(∗
`C ] )
let
let
lower
(x :
bounds
[>
`A
y = (x :
upper
(x :
[>
`B
`A
bounds
[<
redundant
|
are
[<
=
∗)
by
union
by
intersection
`A ; ;
`C ] ) ; ;
combined
=
`A ; ;
`A | ` B | ` D ] ) ; ;
constraints
function
g = (f :
combined
])
`A | ` B | ` C ] )
y = (x :
f =
are
|
[ < `A
`A
|
−>
`B
0
|
are
|
`C
`B
|
dropped
−>
`D ]
∗)
1;;
−>
int );;
∗)
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
Variants polymorphes
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
Sous-typage
Pour en savoir plus
Sous-typage
I Les types variant respectent une notion de sous-typage : un
type variant fermé
fermé
Jacques Garrigue,
w
I Autrement dit,
Chapter 4.2 of the OCaml User's Manual.
v
est un sous-type d'un type variant
si les constructeurs de
constructeurs de
Polymorphic Variants.
v
v
v
sont inclus dans les
w.
est un sous-type de
est également du type
w
si toute valeur de type
w.
I C'est grâce aux variants polymorphe qu'une valeur peut avoir
plusieurs types (à part du cas de la liste vide qui est traité de
façon diérente).
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
Sous-typage
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
Sous-typage
Exemples (sous1.ml)
type
'a
type
'a
vlist
wlist
=
=
Contraintes de types et sous-typage
[ ` Nil
[ ` Nil
|
|
|
` Snoc
of
` Cons
of
` Cons
of
∗
'a
'a
'a
'a
∗
∗
'a
'a
vlist ];;
wlist
wlist ] ; ;
I Nous avons vu qu'on obtient une contrainte
let
let
let
'a
vlist
est
un
s o u s −t y p e
de
'a
wlist
∗)
(borne inférieure
fonction
g
c
alors on peut appliquer la
à toutes les valeurs de type
t1 .
I Si t2 est un sous-type de t1 alors t2 satisfait également la
x =
` Cons
(42 , ` Nil ) ; ;
contrainte
y = ( ` Cons
(42 , ` Nil )
:
int
vlist );;
z = ( ` Cons
(42 , ` Nil )
:
int
wlist );;
g
(éventuellement même un type fermé).
I Si un type t1 satisfait la contrainte
(∗
c
et/ou supérieure) pour le type de l'argument d'une fonction
c,
on peut donc aussi appliquer
valeurs de type
t2 .
g
à toutes les
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
Sous-typage
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
Sous-typage
Exemples (sous2.ml)
Cas d'usage : constructeurs surchargés
On veut plusieurs variantes d'une dénition de type, et partager les
l e t re c
|
g =
` Nil
−>
|
` Cons
(h , r )
|
` Snoc
(h , r )
(∗
wlist
let
(∗
'a
−>
−>
satisfait
x = ( ` Cons
let
vlist
constructeurs (les types sommes ne le permettent pas).
function
true
est
y = ( ` Cons
Exemple : dans la librairie Yojson, Yojson.Raw, Yojson.Safe et
h=1 && ( g
r)
h=2 && ( g
r );;
les
contraintes
(42 , ` Nil )
un
Yojson.Basic fournissent diérents sous-ensemble des constructeurs
suivants :
:
int
s o u s −t y p e
(42 , ` Nil )
:
de
int
type
[
obtenues
wlist )
'a
in
wlist
vlist )
in
g
pour
g
∗)
x ;;
∗)
g
y ;;
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
Sous-typage
let
let
∗)
∗)
∗)
∗)
∗)
∗)
∗)
∗)
∗)
∗)
∗)
∗)
t =
[ `A
x =
`A ; ;
y =
`C ; ;
|
Coercion et Sous-typage
`B ] ; ;
I On peut vouloir considérer une valeur de type ' a vlist comme
une valeur de type ' a wlist .
I Dans ce cas on ne sait plus que la ' a vlist ne contient pas de
types
compatibles
I En OCaml, la coercion d'une valeur v d'un sous-type t1 du
type t2 vers t2 se note (v :
types
vlist partout où
' a wlist est accepté.
∗)
x = y ;;
(∗
S R
B S R
B S
R
B S
S R
B S
B S R
B S
R
S R
S R
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
` Snoc, mais on peut utiliser notre ' a
(∗
]
(∗
(∗
(∗
(∗
(∗
(∗
(∗
(∗
(∗
(∗
(∗
(∗
Sous-typage
Exemples (sous3.ml)
type
|
|
|
|
|
|
|
|
|
|
|
json =
` Assoc of ( s t r i n g ∗ j s o n ) l i s t
` Bool of b o o l
` Float of f l o a t
` F l o a t l i t of s t r i n g
` I n t of i n t
` I n t l i t of s t r i n g
` L i s t of json l i s t
` Null
` S t r i n g of s t r i n g
` S t r i n g l i t of s t r i n g
` Tuple of j s o n l i s t
` Variant of s t r i n g ∗ js on option
incompatibles
(x : t) = y ;;
∗)
omettre le : t1).
t1 :> t2). (On peut parfois
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
Sous-typage
Sous-typage
Exemples (sous4.ml)
type
type
Exemples (sous5.ml)
'a
vlist
=
[ ` Nil
|
'a
wlist
=
[ ` Nil
|
|
let
` Snoc
wlist_of_vlist
let
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
a
:
int
vlist
wlist_of_vlist
l
=
` Cons
` Cons
of
= ( l
` Cons
'a
:
of
of
∗
'a
(1 ,
'a
'a
'a
∗
∗
'a
vlist ];;
'a
wlist
wlist ] ; ;
vlist
:>
'a
wlist );;
vl
l
vl ;;
let
(x :
switch
( match
|
`A
|
`B
:>
= ( l
:
'a
= ( ` Cons ( 7 3 , ` N i l )
|
`B ] )
int
:>
[>
'a
vlist ]);;
vlist );;
=
with
x
−>
−>
[ `A
[ `A
vlist
:
`B
`A
|
`B
|
`C ] )
;;
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
Sous-typage
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
Sous-typage
Conversion, Contrainte, Coercion
Exemples (coercion.ml)
Il ne faut pas confondre ces trois concepts :
I La conversion transforme une valeur d'un type en une valeur
int
en un
float).
Se fait en
OCaml toujours explicitement, à l'aide des fonctions de
conversion.
I Une contrainte de type restreint un type, en ajoutant des
équations pour des variables de type. Elle peut être utile pour
des expressions qui ont un type polymorphe.
I La coercion permet de considérer une valeur d'un type comme
une valeur d'un type plus large. Elle peut être utile dans le
contexte du sous-typage.
open_vlist
open_vlist
` Nil ) ; ;
a ;;
d'un autre type (par ex., un
let
let
type
type
(∗
let
let
(∗
let
(∗
let
t1 =
[ `A
|
`B ] ; ;
t2 =
[ `A
|
`B
contraintes
|
`C
|
`D
incompatibles
];;
∗)
x = ( `A: t1 ) ; ;
y = ( x : t2 ) ; ;
coercion
y = (x
` ` ouvre ' '
:>
contrainte
z = (x
:
le
type
t2 ) ; ;
redondante
[>
`A ] ) ; ;
∗)
∗)
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
Sous-typage
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
Sous-typage
Covariance et contravariance : produits, records, lists
Covariance et contravariance : fonctions
I Comme les variants polymorphes introduisent du sous-typage,
il faut savoir comment ce sous-typage se propage dans le reste
I Le cas des fonctions :
des programmes.
τ10 < τ1
I Le cas des produits :
τ1 < τ10
τ1 → τ2 < τ10 → τ20
τ2 < τ20
τ1 × τ2 < τ10 × τ20
τ2 < τ20
I Le type du résultat de la fonction suit la même direction de
sous-typage que le type fonctionnel (on dit qu'il est co-variant,
I Le cas des enregistrements : pareil
aussi noté avec un
I Le cas des listes :
+),
alors que le type du paramètre va dans
le sens inverse (on dit qu'il est contra-variant, aussi noté avec
un
τ1 < τ10
-).
τ1 list < τ10 list
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
Sous-typage
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
Sous-typage
D'où vient la contravariance ?
I Étant donnée une fonction
Exemples (sous6.ml)
f : τ1 → τ2
quelconque.
I Quand peut-on aussi la considérer comme une fonction
τ0 → τ0 ?
1
2
1. Il faut que le résultat de f soit aussi du type τ20 :
τ2 < τ20
2. Il faut que toute valeur de type τ10 soit acceptée comme
argument à la fonction f :
τ10 < τ1
let
f
:
[ `T
let
g
:
[
|
`T ]
(∗
le
type
(f
:>
[
(∗
le
type
de
(g
:>
[
|
−>
de
f
−>
`T ]
`T
`Z ]
−>
int
int
est
=
un
=
function
function
s o u s −t y p e
`T
`T
−>
du
−>
4
1
|
`Z
de
g
∗)
−>
2;;
;;
type
int );;
g
`Z ]
n ' est
−>
pas
int );;
un
s o u s −t y p e
du
type
de
f
∗)
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
Sous-typage
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
Sous-typage
Les annotations de variance sur les types abstraits
I Il est important de connaître la variance des paramètres des
fonctions, pour savoir déterminer si un type fonctionnel est
sous-type d'un autre.
Exemples (abstrait1.ml)
module type
type + ' a
end ; ;
POS =
sig
t
I Le compilateur détermine cette information pour tous les types
qu'il connaît, mais il ne peut pas le faire pour les types
abstraits dans les interfaces des modules.
type
'a
t
I C'est le programmeur qui peut indiquer la variance avec un +
ou un -
type
type
+' a
t
(−'a )
tt
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
Sous-typage
module type NEG
type − ' a t
end ; ;
(∗
Erreur
( ∗ OK
module
type
end ; ;
module
type
end ; ;
(∗
∗)
'a
Erreur
module
type
end ; ;
struct
P : POS =
'a∗'a
t =
∗)
struct
N : POS =
'a
' a−>b o o l
t =
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
Sous-typage
Exemples (abstrait2.ml)
module
type
end ; ;
( ∗ OK
sig
∗)
P : NEG =
'a
=
Exemples (sous8.ml)
t =
struct
let
f1 =
fun
( ` Nombre
x)
−>
x =
0;;
let
f2 =
fun
( ` Nombre
x)
−>
x =
0.0;;
'a∗'a
(∗
let
∗)
N : NEG =
'a
t =
struct
' a−>b o o l
Attention
f
x = f1
:
type
x
||
f2
non
x ;;
habite
!
∗)
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
Sous-typage
Types non habités
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
Sous-typage
Résumé des variants polymorphes
I Les variants polymorphes permettent d'écrire des programmes
I Dans l'exemple du transparent précédent : La dénition de f
force le type de l'argument du constructeur ` Nombre a être un
int et un oat à la fois ( int & oat ).
I Dans cet exemple, cette contrainte est impossible à satisfaire.
plus exibles que les types sommes habituels.
I Mais ils ont leurs inconvénients :
I
I
f est donc bien typée, mais on ne pourra jamais l'appliquer car
il y a aucune valeur de ce type.
I
ils induisent des problèmes de typage parfois complexes
moins de vérications sont faites statiquement, et il devient
facile d'utiliser un constructeur qui n'existe pas, ou avec un
mauvais type, sans que le compilateur ne dise rien
ils induisent une petite perte d'ecacité des programmes.
I Donc : à utiliser seulement si on peut en tirer prot.
Programmation Fonctionnelle Avancée 8 : Utilisation avancée du system de typage : variants polymorphes et sous-typage
Sous-typage
Pour en savoir plus
Jacques Garrigue.
Code reuse through polymorphic variants.
In Workshop on Foundations of Software Engineering, 2000.
http://www.math.nagoya-u.ac.jp/
~garrigue/papers/fose2000.html.
Available from
Téléchargement