1.6 Unification
La grande différence dans l'algorithme de typage du l-calcul et celui présenté ici provient
de l'algorithme d'unification. dans le premier cas, la fonction TYPE
retournait la liste
des substitutions (l'unificateur principal UP) à appliquer pour que deux termes t1 et t2
vérifient UP(t1)=UP(t2). Cet algorithme bien que juste n'est pas forcément très efficace. En mini-ML,
Les substitutions trouvées sont immédiatement appliquées aux types en effectuant une modification physique
de ces types.
Deux problèmes se posent :
-
la vérification d'occurrences, quand une variable de type est remplacée par un autre type, ce second
type ne doit pas contenir d'occurrence de cette première variable. La fonction
occurs
réalise
ce test.
- Lorsqu'une inconnue se voit attribuer comme valeur une autre inconnue, on crée une chaîne d'indirection
qu'il faut alors simplifier :
Var_type (ref (Var_type ( ref (Instanciated t))))
deviendra alors seulement t
.
La fonction shorten
réalise ce travail.
# let
occurs
n
t
=
List.mem
n
(vars_of_type
t);;
val occurs : int -> ml_type -> bool = <fun>
# let
rec
shorten
=
function
Var_type
(vt)
as
tt
->
(match
!
vt
with
Unknown
_
->
tt
|
Instanciated
((Var_type
_
)
as
t)
->
let
t2
=
shorten
t
in
vt
:=
Instanciated
t;
t2
|
Instanciated
t
->
t
)
|
t
->
t;;
val shorten : ml_type -> ml_type = <fun>
La fonction unify_types
prend deux types, modifie leur taille (par la fonction shorten
)
et les rend égaux ou échoue.
# let
rec
unify_types
(t1,
t2)
=
let
lt1
=
shorten
t1
and
lt2
=
shorten
t2
in
match
(lt1,
lt2)
with
|
Var_type
(
{contents=
Unknown
n}
as
occn
),
Var_type
{contents=
Unknown
m}
->
if
n=
m
then
()
else
occn:=
Instanciated
lt2
|
Var_type
({contents=
(Unknown
n)}
as
occn),
_
->
if
occurs
n
lt2
then
raise
(Type_error(Clash(lt1,
lt2)))
else
occn:=
Instanciated
lt2
|
_
,
Var_type
({contents=
(Unknown
n)})
->
unify_types
(lt2,
lt1)
|
Const_type
ct1,
Const_type
ct2
->
if
ct1=
ct2
then
()
else
raise
(Type_error(Clash(lt1,
lt2)))
|
Pair_type
(t1,
t2),
Pair_type
(t3,
t4)
->
unify_types
(t1,
t3);
unify_types(t2,
t4)
|
List_type
t1,
List_type
t2
->
unify_types
(t1,
t2)
|
Fun_type
(t1,
t2),
Fun_type
(t3,
t4)
->
unify_types
(t1,
t3);
unify_types(t2,
t4)
|
_
->
raise(Type_error(Clash(lt1,
lt2)));;
val unify_types : ml_type * ml_type -> unit = <fun>