Programmation Fonctionnelle Avancée 9 : Types phantomes et

Transcription

Programmation Fonctionnelle Avancée 9 : Types phantomes et
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types fantômes
Les types fantômes (phantom types)
Programmation Fonctionnelle Avancée
9 : Types phantomes et GADT
I Un type fantôme est un type polymorphe dont au moins un
paramètre de type n'est pas utilisé dans sa dénition. En voici
Ralf Treinen
Université Paris Diderot
UFR Informatique
Institut de Recherche en Informatique Fondamentale
[email protected]
un :
type
'a
t =
float ;;
I Tant que les dénitions restent visibles, toutes les instances
des types fantômes sont équivalentes pour le compilateur :
I Les égalités char t = oat = string t sont connues du
typeur, qui ne regarde que le corps de la dénition : oat .
28 novembre 2016
c
Roberto Di Cosmo et Ralf Treinen
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types fantômes
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types fantômes
Exemples (phantom1.ml)
Les types fantômes (phantom types)
type
let
let
'a
t =
float ;;
(x :
char
t) =
(y :
string
x +. y ; ;
I Les choses deviennent bien plus intéressantes si ces égalités se
3.0;;
t) =
5.0;;
retrouvent
cachées
par la dénition d'un type abstrait dans
l'interface d'un module.
I Cela permet par exemple d'avoir deux versions diérentes du
type
float
pour des unités de mesure diérentes.
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types fantômes
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types fantômes
Exemples (phantom2.ml)
Exemples (phantom3.ml)
module type LENGTH = s i g
type ' a t
v a l m e t e r s : f l o a t −> [ ` M e t e r s ]
v a l f e e t : f l o a t −> [ ` F e e t ] t
v a l ( + . ) : ' a t −> ' a t −> ' a t
v a l t o _ f l o a t : ' a t −> f l o a t
end ; ;
module L e n g t h : LENGTH = s t r u c t
type ' a t = f l o a t
l e t meters f = f
let feet f = f
l e t (+.) = P e r v a s i v e s . ( + . )
let to_float f = f
end ; ;
t
open
let
let
Length
m1 = m e t e r s
f1 =
feet
10.;;
40.;;
m1 +. m1 ; ;
f1
+.
f1 ; ;
to_float
m1 +.
( f1
+.
f1 ) ; ;
f1 ; ;
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types fantômes
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types fantômes
Même les meilleurs peuvent en avoir besoin
Utiliser les types fantômes
I On peut essayer de pousser cet exemple plus loin, et coder des
informations plus nes dans le paramètre fantôme.
I Dans l'exemple suivant, nous essayons d'appliquer ce principe
pour raner un type de listes en listes vides et listes non
vides.
I Nous dénissons deux types abstraites
vide
et
nonvide
nous servent seulement pour faire cette distinction.
qui
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types fantômes
module type LISTE = s i g
type v i d e
type n o n v i d e
type ( ' a , ' b ) t
val l i s t e v i d e : ( vide , 'b) t
v a l c o n s : ' b −> ( ' a , ' b ) t −> ( n o n v i d e , ' b ) t
v a l head : ( n o n v i d e , ' b ) t −> ' b
end ; ;
module L i s t e : LISTE = s t r u c t
type v i d e
type n o n v i d e
type ( ' a , ' b ) t = ' b l i s t
let l i s t e v i d e = [ ]
l e t cons v l = v : : l
l e t head = f u n c t i o n [ ] −> a s s e r t f a l s e | a : : _ −> a
end ; ;
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types fantômes
Listes vides et non vides
I L'exemple précédent permet de distinguer les listes vides et
non vides aux
niveau de typage.
I Problème : quel est le type de la fonction tail ?
I Son argument doit être du type (nonvide ,' b) t. Mais le
résultat peut être vide ou non vide.
I Si on utilise des variants polymorphes comme paramètres, le
sous-typage des variants polymorphes donne des types plus
précis pour les constructeurs.
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types fantômes
Exemples (phantom5.ml)
open
Liste ;;
listevide ;;
cons
3
head
( cons
listevide ;;
3
listevide );;
( ∗ e r r e u r de t y p a g e ! ∗ )
head
listevide ;;
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types fantômes
module type LISTEVP = s i g
type ( ' a , ' b ) t
val l i s t e v i d e : ( [ ` Vide ] , ' b ) t
v a l c o n s : ' b −> ([ < ` V i d e | ` N o n v i d e ] , ' b ) t
−> ( [ ` N o n v i d e ] , ' b ) t
v a l head : ( [ ` N o n v i d e ] , ' b ) t −> ' b
v a l t a i l : ( [ ` N o n v i d e ] , ' b ) t −> ([ < ` V i d e | ` N o n v i d e ]
end ; ;
module L i s t e V P : LISTEVP = s t r u c t
type ( ' a , ' b ) t = ' b l i s t
let l i s t e v i d e = [ ]
l e t cons v l = v : : l
l e t head = f u n c t i o n [ ] −> a s s e r t f a l s e | a : : _ −> a
l e t t a i l = f u n c t i o n [ ] −> a s s e r t f a l s e | _ : : t −> t
end ; ;
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types fantômes
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types fantômes
Exemples (phantom7.ml)
Pourquoi cet erreur ?
open
I Notre système de type est maintenant trop faible pour éviter
ListeVP ; ;
des erreurs d'applications de fonctions à des listes vides.
I La distinction en
listevide ;;
let
x = cons
3
listevide ;;
head
x ;;
head
listevide ;;
tail
( cons
1
tail
( tail
( cons
non vide
est trop grossière.
I Pour faire cela nous devrons représenter chaque nombre
naturel par un
type
diérent : nous utilisons un type zero, et
un constructeur de type ' a succ.
listevide );;
listevide ));;
et
I Idée : coder la longueur de la liste dans le type !
(∗ type e r r o r ∗)
1
vide
I Ainsi, le nombre naturel 2 est représenté par le type
zero succ succ (notation postx pour les applications de
(∗ a s s e r t f a i l u r e ∗)
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types fantômes
module t y p e LISTECOUNT = s i g
type ( ' a , ' b ) t
type zero
type ' a succ
v a l l i s t e v i d e : ( zero , ' b ) t
v a l e s t v i d e : ( ' a , ' b ) t −> b o o l
v a l c o n s : ' b −> ( ' a , ' b ) t −> ( ' a s u c c , ' b ) t
v a l head : ( ' a s u c c , ' b ) t −> ' b
v a l t a i l : ( ' a s u c c , ' b ) t −> ( ' a , ' b ) t
end ; ;
module L i s t e c o u n t : LISTECOUNT = s t r u c t
type ( ' a , ' b ) t = ' b l i s t
type zero
type ' a succ
let listevide = []
l e t e s t v i d e = f u n c t i o n [ ] −> t r u e | _ −> f a l s e
l e t cons v l = v : : l
l e t head = f u n c t i o n [ ] −> a s s e r t f a l s e | a : : _ −> a
l e t t a i l = f u n c t i o n [ ] −> a s s e r t f a l s e | _ : : l −> l
end ; ;
constructeurs de type).
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types fantômes
Exemples (phantom9.ml)
open
Listecount ; ;
let
l 4 = cons
1
let
l1 =
( tail
tail
head
l1 ; ;
tail
( tail
l1 ) ; ;
( cons
2
( cons
( tail
3
l4 ) ) ; ;
( cons
4
listevide )));;
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types fantômes
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types fantômes
Listes avec codage de longueur
Cas d'utilisation : Lablgtk2
On utilise les types fantômes pour typer les widgets (avec des
variants polymorphes) :
I Les deux derniers transparents poussent l'exercice encore plus
loin : on encode la longueur de la liste dans un type fantôme
(en codage unaire).
I L'utilité est limitée : on peut encore écrire map avec ces types
de données, mais pas la fonction append (pourquoi ?).
type
type
type
type
(−'a )
gtkobj
widget =
[ ` widget ]
container
box =
=
[ ` widget | ` container ]
[ ` w i d g e t | ` c o n t a i n e r | ` box ]
Cela autorise la coercion sûre entre les classes :
(mybox : box gtkobj :> container gtkobj )
Voir
http://lablgtk.forge.ocamlcore.org/
et le message de
Jacques Garrigue de septembre 2001
http://caml.inria.fr/pub/ml-archives/caml-list/2001/
09/2915ad47e671450ac5acefe4d8bd76fb.en.html
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types fantômes
Cas d'utilisation : contrôle d'accès dans
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types fantômes
libvirt
I Libvirt is a C toolkit to interact with the virtualization
capabilities of recent versions of Linux (and other OSes). The
library aims at providing a long term stable C API for dierent
virtualization mechanisms. It currently supports QEMU, KVM,
XEN, OpenVZ, LXC, and VirtualBox.
I Libvirt utilise des types fantômes pour le contrôle d'accès aux
ressources virtualisées.
http://camltastic.blogspot.fr/2008/05/
phantom-types.html
I Voir :
Exemples (libvirt1.ml)
module type CONNECTION = s i g
type ' a t
v a l c o n n e c t _ r e a d o n l y : u n i t −> [ ` R e a d o n l y ] t
v a l c o n n e c t : u n i t −> [ ` R e a d o n l y | ` R e a d w r i t e ]
v a l s t a t u s : [ > ` R e a d o n l y ] t −> i n t
v a l d e s t r o y : [ > ` R e a d w r i t e ] t −> u n i t
end ; ;
module C o n n e c t i o n : CONNECTION = s t r u c t
type ' a t = i n t
l e t count = r e f 0
l e t connect_readonly () = i n c r count ; ! count
l e t connect () = i n c r count ; ! count
let status c = c
let destroy c = ()
end ; ;
t
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types fantômes
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types fantômes
module t y p e HTML = s i g
t y p e +'a e l t
v a l p c d a t a : s t r i n g −> [> ` Pcdata ] e l t
v a l s p a n : [< ` Span | ` Pcdata ] e l t l i s t
−> [> ` Span ] e l t
v a l d i v : [< ` Div | ` Span | ` Pcdata ] e l t
−> [> ` Div ] e l t
end
;;
Exemples (libvirt2.ml)
open C o n n e c t i o n ; ;
l e t conn_ro = c o n n e c t _ r e a d o n l y
status
destroy
let
conn_ro ; ;
(∗ e r r o r ∗)
conn_rw = c o n n e c t
status
destroy
();;
conn_ro ; ;
module Html : HTML =
struct
t y p e raw =
| Node o f s t r i n g ∗ raw l i s t
| Pcdata o f s t r i n g
t y p e ' a e l t = raw
l e t p c d a t a s = Pcdata s
l e t d i v l = Node ( " d i v " , l )
l e t s p a n l = Node ( " s p a n " , l )
end ; ;
();;
conn_rw ; ;
conn_rw ; ;
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types fantômes
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types fantômes
Exemples (html2.ml)
Bilan des types fantômes
open Html ; ;
let x = div
[
pcdata
""
list
];;
avantages :
( ∗ e r r e u r , pas de d i v dans l e s span ∗ )
l e t x ' = span [ d i v [ ] ] ; ;
( ∗ OK ∗ )
l e t x ' ' = span [ span [ ]
l e t f s = div [ s ; pcdata
l e t f ' s = d i v [ s ; span
l e t f ' ' s = d i v [ s ; span
I
étiquettes
sur les types qui permettent
I un contrôle
statique
du bon usage des données
I sans aucune pénalité à l'exécution (les types sont
eacés à la compilation)
];;
limitations : expressivité limitée
"" ] ; ;
[]];;
[];
pcdata
""
];;
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types fantômes
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types algébriques généralisés
Pour en savoir plus
Limitation des types algébriques
I Il y a des situations dans lesquelles
Daan Leijen and Erik Meijer.
on sait
qu'un ltrage est
complet, mais le compilateur OCaml ne le voit pas.
Domain specic embedded compilers.
SIGPLAN Not., 35(1) :109122, December 1999.
I C'est le cas dans le code (simplié) suivant : dans la deuxième
branche, nous savons que x = a:: r, donc le deuxième match
est exhaustive.
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types algébriques généralisés
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types algébriques généralisés
Exemples (gadt1.ml)
Vers des GADT
I De l'anglais :
let
|
|
silly
x =
match
−> 1
a : : r −> match
x
I Il s'agit d'une extension du langage (contrairement aux types
with
phantômes).
[]
x
with
(a ' : : r ')
Generalised Algebraic Data Types
−>
( ∗ p a t t e r n matching non e x h a u s t i v e ∗ )
2;;
I Première étape de l'extension : on sépare
constructeurs de la
le type envoyé par les
dénition du type : cela permet de préciser,
et distinguer, le résultat de chaque constructeur.
I Syntaxe alternative (et plus générale) pour déclarer les
constructeurs d'un type somme
I Attention : à partir d'ici nous avons besoin de OCaml
> 4.00.
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types algébriques généralisés
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types algébriques généralisés
Exemples (gadt2.ml)
Exemples (gadt3.ml)
type
type
type
empty
nonempty
'a
|
Cons
|
Nil
il
:
:
=
int
∗
empty
'a
il
−>
nonempty
il
il
( ∗ j u s q u ' i c i , t o u t va b i e n ∗ )
l e t h e a d = f u n c t i o n C o n s ( x , r ) −>
x ;;
( ∗ mais l e t y p e u r e x i g e que t o u s l e s m o t i f s
ont l e meme t y p e ! ∗ )
l e t tail_or_empty = function
−>
|
Nil
|
( C o n s _)
( ∗ On p e u t a i d e r l e t y p e u r , e t l u i d i r e
que t a i l _ o r _ e m p t y e s t une f o n c t i o n a y a n t
un t y p e p o l y m o r p h e . Chaque c a s p e u t donc
a v o i r une i n s t a n c e d i f f e r e n t e de ce t y p e .
∗)
let
tail_or_empty
−>
|
Nil
|
( C o n s _)
:
type
a
.
a
as
−>
l
hd
=
function
1
as
l
−>
hd
l ;;
Exemples (gadt4.ml)
Exemples (gadt5.ml)
( ∗ V e r s i o n de s i l l y q u i ne donne p l u s de w a r n i n g ∗ )
−>
int
l ;;
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types algébriques généralisés
silly
−>
1
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types algébriques généralisés
let
il
:
|
Nil
|
( C o n s _)
type
a
.
a
il
−>
int
=
function
1
as l −>
( ∗ h e r e we know t h a t ' a = nonempty ! ∗ )
match l with C o n s ( x , _) −> 2 ; ;
( ∗ Exemple : l e s l i s t e s v i d e s / n o n v i d e s , e n c o r e ∗ )
type
type
type
empty
nonempty
( 'a ,
'b)
:
t =
|
Nil
|
Cons
:
( empty ,
let
hd =
function
'b
∗
'b)
( 'a ,
t
'b)
Cons
t
−>
(x , r )
( nonempty ,
−>
x ;;
'b)
t ;;
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types algébriques généralisés
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types algébriques généralisés
Exemples (gadt7.ml)
Exemples réalistes : interpréteur (sans GADT)
l e t re c l e n g t h
= function
−>
|
Nil
|
( Cons
l e t re c
:
type
b.
fun
f
−>
t
int
I Interpréteur pour un petit langage d'expressions
:
type
−>
a
1 + ( length
b
c.
(a , b)
=
(a , b)
0
(_, r ) )
map
a
(b
t
−>
−>
r );;
I Types de base int, bool, plus un
(a , c)
P(int,P(bool,bool)),
t
( Cons
(x , r ))
−>
Cons ( f
. . .)
I On veut avoir un seul type d'expressions
−> f u n c t i o n
| N i l −> N i l
|
x , map
f
r );;
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types algébriques généralisés
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types algébriques généralisés
Exemples (gadt8.ml)
Exemples (gadt9.ml)
l e t re c
|
( ∗ e x p r e s s i o n s s a n s GADT, a l a L3 ∗ )
type
|
|
|
|
expr =
of i n t
B o o l of b o o l
P r o d of e x p r ∗ e x p r
I f T h e n E l s e of e x p r ∗
(∗ v a l e u r s ∗)
type r e s = I of
eval
Int
x
Bool
|
Prod
|
IfThenElse
match
∗
=
function
−> I x
b −> B b
( e1 , e 2 ) −>
|
Int
expr
P.
I Nombre inni de types d'expressions (int, bool, P(int,bool),
−>
c)
constructeur de type
|
B b
|
_
( eval
( e1 , e2 , e 3 )
( eval
−> i f
−>
P
e1 , e v a l
e2 )
−>
with
then e v a l
e1 )
b
failwith
else
e2
" Nonboolean
eval
condition
e3
in
an
ITE ! " ; ;
expr ; ;
( ∗ e x c e p t i o n p e n da n t l ' e x e c u t i o n ∗ )
int
|
B
of
bool
|
P
of
eval
res
∗
( IfThenElse
(( Int
0) ,( Int
1) ,( Int
2)));;
res ; ;
( ∗ OK ∗ )
eval
( IfThenElse
( ( Bool
eval
( IfThenElse
( ( Bool
true ) , ( I n t 3) ,( I n t 4 ) ) ) ; ;
true ) , ( Bool f a l s e ) , ( Bool true
)))
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types algébriques généralisés
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types algébriques généralisés
Limitations de l'interpréteur sans GADT
Exemples (gadt10.ml)
( ∗ e x p r e s s i o n a v e c GADT ∗ )
Comme on ne sait pas classier les expressions par leur type, on est
type
obligé de :
I aplatir les expressions dans un type expr
|
I aplatir les résultats dans un type res
|
I écrire la fonction eval en traitant les possibles cas d'erreur qui
viennent du fait que toute expression peut apparaître partout
|
|
_ expr =
−> i n t e x p r
B o o l : b o o l −> b o o l e x p r
P r o d : ' a e x p r ∗ ' b e x p r −>
IfThenElse : bool expr ∗ ' a
−> ' a e x p r
Int
:
int
( 'a
expr
∗
'b)
expr
'a
expr
∗
;;
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types algébriques généralisés
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types algébriques généralisés
Exemples (gadt11.ml)
Exemples réalistes : fonctions composables
l e t re c
eval
type
:
|
Int
|
Bool
−> x
b −> b
|
Prod
( e1 , e 2 )
|
IfThenElse
if
x
( eval
a.
a
expr
−>
a =
function
fonctions qui se composent ?
−>
( eval
( b , e1 , e 2 )
b)
then
e1 ) , ( e v a l
e2 )
f
( eval
e1 )
else
( IfThenElse
(( Int
0) ,( Int
f
f
1
2
3
n
A3 −→
. . . −→
An+1
A1 −→
A2 −→
−>
( eval
e2 ) ; ;
f
I Cela semble impossible avec le langage vu en L3.
I Avec GADT, on peut donner un type précis qui permet d'écrire
( ∗ e r r e u r de t y p a g e ! ∗ )
eval
I Comment typer une liste [ f1 ; f2 ; f3 ;...; fn ] contenant des
1) ,( Int
2)));;
du code bien typé.
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types algébriques généralisés
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types algébriques généralisés
Exemples (gadt12.ml)
Variables de types et GADT
type
( 'a , ' b)
|
Nilf :
|
Consf :
cfl
=
( 'a , ' a)
cfl
−>
'b)
( 'a
∗
( 'b , ' c)
cfl
l e t re c c o m p u t e : type a b . a −>
= fun x −>
function
| N i l f −> x ( ∗ h e r e ' a = ' b ∗ )
|
Consf
(f , rl )
−>
let
bad = C o n s f ( (
let
good = C o n s f ( (
compute
fun
x
−>
(f
−>
(a , b)
x)
( 'a , ' c)
cfl
−>
cfl ;;
b
I Dans cet exemple, on voit qu'on peut utiliser des variables de
type qui n'apparaissent pas dans le résultat du constructeur :
c'est le cas de ' b.
I Il s'agit de variables dites
existentielles,
parce que le type de
Consf
∀acb.(a → b) ∗ (b, c) cfl → (a, c) cfl
rl ;;
truncate
x) ,
peut se lire comme
∀ac(∃b.(a → b) ∗ (b, c) cfl) → (a, c) cfl
Consf ( s t ri ng _o f _f lo at , N i l f ) ) ; ;
fun
x
−>
truncate
x) ,
Consf ( string_of_int , N i l f ) ) ; ;
compute
3.5
good ; ;
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types algébriques généralisés
Exemples réalistes : fonctions d'impression (sans GADT)
functional unparsing d'Olivier Danvy, le format est
combinaison de fonctions d'achage élémentaires.
I Avec le
une
I On peut donner un type précis au format et à la fonction
d'impression :
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types algébriques généralisés
type ' a t y =
| Int : i n t ty
| String : s t r i n g ty
| P a i r : ( ' a t y ∗ ' b t y ) −> ( ' a ∗ ' b ) t y ; ;
l e t r e c p r i n t f : type a . a t y −> a −> u n i t = fun f o r m a t v −>
match f o r m a t with
| I n t −> p r i n t _ i n t v ( ∗ i c i v e s t i n t ∗ )
| S t r i n g −> p r i n t _ s t r i n g v ( ∗ i c i v e s t s t r i n g ∗ )
| P a i r ( b , c ) −> p r i n t f b ( f s t v ) ; p r i n t f c ( snd v )
(∗ i c i v e s t une p a i r e ∗)
;;
l e t ( ∗∗ ) = fun x y −> P a i r ( x , y ) ; ;
p r i n t f ( ( I n t ∗∗ S t r i n g ) ∗∗ I n t ) ( ( 4 , " and t h e n " ) , 5 ) ; ;
Programmation Fonctionnelle Avancée 9 : Types phantomes et GADT
Types algébriques généralisés
Pour en savoir plus
Hongwei Xi, Chiyan Chen, and Gang Chen.
Guarded recursive datatype constructors.
In Proceedings of the 30th ACM SIGPLAN Symposium on
Principles of Programming Languages, pages 224235, New
Orleans, January 2003.
François Pottier and Yann Régis-Gianas.
Stratied type inference for generalized algebraic data types.
In Conference record of the 33rd ACM SIGPLAN-SIGACT
symposium on Principles of programming languages, POPL
'06, pages 232244, New York, NY, USA, 2006. ACM.
Dimitrios Vytiniotis, Simon L. Peyton Jones, Tom Schrijvers,
and Martin Sulzmann.
Outsidein(x) modular type inference with local assumptions.
J. Funct. Program., 21(4-5) :333412, 2011.