(** Map of an id to a type *) module IdentifierMap = Map.Make (Identifier) (** Map type *) type t = Type.t IdentifierMap.t (* Empty substitution *) let empty = IdentifierMap.empty (** Create a substitution with one element *) let singleton id ty = IdentifierMap.singleton id ty (** Apply substitution to a type *) let rec apply subst = function | Type.Var id as t -> (match IdentifierMap.find_opt id subst with | Some ty' -> apply subst ty' | None -> t) | Type.Int -> Type.Int | Type.Product (ty1, ty2) -> Type.Product (apply subst ty1, apply subst ty2) | Type.Arrow (ty1, ty2) -> Type.Arrow (apply subst ty1, apply subst ty2) ;; (** Compose two substitutions *) let compose s2 s1 = IdentifierMap.merge (fun _ ty1 ty2 -> match ty1, ty2 with (* If we have 2, we pick one of them *) | Some ty1, Some _ -> Some (apply s2 ty1) (* If we have 1, we pick the one we have *) | Some ty1, None -> Some (apply s2 ty1) | None, Some ty2 -> Some (apply s2 ty2) (* If we have 0, we return nothing *) | None, None -> None) s1 s2 ;;