## Code to help with CS152 Assignment: ML Type Inference

To print type schemes, we use: <<*>>= fun separate (zero, sep) = (* useful for printing *) let fun s [] = zero | s [x] = x | s (h::t) = h ^ sep ^ s t in s end local (* precedences *) val CONp = 3 val STARp = 2 val ARROWp = 1 val NONEp = 0 fun parens s = "(" ^ s ^ ")" fun bracket(s, context, prec : int) = if prec <= context then parens s else s fun p(context, CONty ("tuple", l)) = bracket(ptuple l, context, STARp) | p(context, CONty (n, [])) = n | p(context, CONty (n, [t])) = p(CONp, t) ^ " " ^ n | p(context, CONty (n, l)) = "(" ^ separate("", ", ") (map ?? l) ^ ") " ^ n | p(context, VARty v) = "'" ^ v | p(context, ARROWty (arg, ret)) = bracket(p(ARROWp, arg) ^ " -> " ^ p(ARROWp, ret), context, ARROWp) and ptuple l = separate("unit", " * ") (map (fn t => p(STARp, t)) l) and ?? ty = p(NONEp, ty) in val ?? = ?? val ptuple = ptuple end @ @ Here are a bunch of functions on types, including finding free type variables and putting types into canonical form by making the variables [['a]], [['b]], etc. <<*>>= fun member(x, []) = false | member(x, h::t) = x = h orelse member(x, t) fun insert(x, l) = if member(x, l) then l else x::l fun freevars t = let fun f(VARty v, l) = insert(v, l) | f(CONty(_, args), l) = foldr f l args | f(ARROWty(arg, ret), l) = f(ret, f(arg, l)) in f(t, []) end local val n = ref 1 in fun freshtyvar _ = VARty ("t" ^ makestring (!n) before (n := !n + 1)) end @ Note that to put things in canonical form, I first make all the free type variables fresh type variables, so that when I start making type variables into [["a"]] and so on, I don't collide with variables that are already there. <<*>>= fun canonical_tyvar n = VARty (if n < 26 then str(chr (ord #"a" + n)) else "v" ^ makestring (n - 25)) fun canonicalize ty = let exception Impossible fun s ([], to_fresh, to_canon, count) = to_canon o to_fresh | s (v::rest, to_fresh, to_canon, count) = (case freshtyvar() of (ty' as (VARty v')) => s(rest, v |--> ty' o to_fresh, v' |--> canonical_tyvar count o to_canon, count+1) | _ => raise Impossible) in s(freevars ty, fn x => x, fn x => x, 0) ty end fun canonicalize_pair(t1, t2) = let exception Impossible in case canonicalize (CONty("tuple", [t1, t2])) of CONty("tuple", [t1, t2]) => (t1, t2) | _ => raise Impossible end @ If you don't want to use functions to represent substitution, here's an alternative suggestion: <>= infix 7 |--> infix 3 o' datatype subst = op |--> of string * ty | op o' of subst * subst | idsubst fun apply (sigma o' sigma') ty = apply sigma (apply sigma' ty) | apply idsubst ty = ty | apply (v |--> t) ty = (* you write this part *) @ I haven't tested this code, but if you use it, you'll be able to print substitutions by defining a suitable function. You'll use [[o']] instead of [[o]] to compose them, of course...