3.9 Impression des types et des erreurs
Comme les variables de types sont codées à l'aide d'entiers, il serait particulièrement
désagréable d'avoir un affichage de types dépendant de cette numérotation.
Pour cela, pour chaque expression globale est crée une liste d'association des numéros de variables
de types et des symboles pour les types polymorphes.
Les constantes de types sont affichées directement par la fonction print_consttype
:
let print_consttype = function
*
Int_type ® print_string ``int
''
*
Float_type ® print_string ``float
''
*
String_type ® print_string ``string
''
*
Bool_type ® print_string ``bool
''
*
Unit_type ® print_string ``unit
''
*
;;
*
print_consttype : consttype ® unit = áfunñ
La fonction var_name
retourne une chaîne de caractères unique pour chaque entier
passé en argument :
let ascii i = char_for_read (char_of_int i);;
*
ascii : int ® string = áfunñ
let var_name n =
*
let rec name_of n =
*
let q,r = ((n / 26), (n mod 26))
*
in
*
if q=0 then ascii (96+r)
*
else (name_of q)^
(ascii (96+r))
*
in ``'
''^
(name_of n)
*
;;
*
var_name : int ® string = áfunñ
La fonction principale est l'impression d'un schéma de type. Le seul problème est
de trouver le nom d'une variable de types. la fonction locale names_of
retourne
les variables quantifiées, chacune associée à une chaîne de caractères particulière.
Si une variable de type n'est pas donc cet ensemble une exception est déclenchée, car il ne peut avoir
d'expression globale contenant des variables de type non quantifiées.
let print_quantified_type (Forall(gv,t)) =
*
let names =
*
let rec names_of = function
*
(n,[ ]) ® [ ]
*
(n,(v1::lv)) ® (var_name n)::(names_of (n+1,lv))
*
in (names_of (1,gv))
*
in
*
let var_names = combine (rev gv,names)
*
in
*
let rec print_rec = function
*
Var_type (ref(Instanciated t)) ® print_rec t
*
Var_type (ref(Unknown n)) ®
*
let name = (try assoc n var_names
*
with Not_found ® raise (Failure ``Non quantified variable in type
''))
*
in print_string name
*
Const_type ct ® print_consttype ct
*
Pair_type(t1,t2) ® print_string ``(
'' print_rec t1
*
print_string `` *
'' print_rec t2 print_string ``)
''
*
List_type t ® print_string ``((
'' print_rec t print_string ``) list)
''
*
Fun_type(t1,t2) ® print_string ``(
'' print_rec t1
*
print_string `` ->
'' print_rec t2 print_string ``)
''
*
in
*
print_rec t
*
;;
*
print_quantified_type : quantified_type ® unit = áfunñ
L'impression d'un type simple utilise l'impression des chémas de type en créant pour
l'occasion une quantification sur toutes les variables libres du type.
let print_type t = print_quantified_type (Forall(free_vars_of_type ([ ],t),t));;
*
print_type : ml_type ® unit = áfunñ
Il est fort intéressant d'afficher les causes d'un échec de typage, comme
par exemple les types mis en cause lors d'une erreur de typage ou le nom
d'une variable indéfinie.
La fonction typing_handler
reçoit en argument une fonction de typage, un environnement et
une expression à typer. Elle capture les exceptions dues à une erreur de typage, affiche un
message plus clair et déclenche une nouvelle exception.
let typing_handler typing_fun env expr =
*
reset_unknowns()
*
try typing_fun env expr
*
with
*
type_error (Clash(lt1,lt2)) ®
*
print_string ``Type clash between
''print_type lt1
*
print_string `` and
''print_type lt2 print_newline()
*
failwith ``type_check
''
*
type_error (Unbound_var s) ®
*
print_string ``Unbound variable
''
*
print_string s print_newline()
*
failwith ``type_check
''
*
;;
*
typing_handler : (a ® b ® g) ® a ® b ® g = áfunñ