Précédent Remonter Suivant

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";;
val print_consttype : consttype -> unit = <fun>


La fonction var_name retourne une chaîne de caractères unique pour chaque entier passé en argument :

# let string_of_char c =
let s = " " in s.[0] <- c; s;;
val string_of_char : char -> string = <fun>
# let var_name n =
let rec name_of n =
let q,r = ((n / 26), (n mod 26)) in
if q=0 then string_of_char(Char.chr (96+r))
else (name_of q)^(string_of_char(Char.chr (96+r)))
in
"'"^(name_of n);;
val 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 = List.combine (List.rev gv) names in
let rec print_rec = function
Var_type {contents=(Instanciated t)} ® print_rec t
| Var_type {contents=(Unknown n)} ®
let name =
( try List.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;;
val 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));;
val 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";;
val typing_handler : ('a -> 'b -> 'c) -> 'a -> 'b -> 'c = <fun>



Précédent Remonter Suivant