


@ 249,8 +249,8 @@ module Make





This constraint requires [∃α.c1(α)] to be satisfied. This is required





even if the term variable [x] is not used in [c2].










Inside [c2], an instantiation constraint of the form [x(β)] is logically





equivalent to [c1(β)]. In other words, a [let] constraint acts like a





Inside [c2], an instantiation constraint of the form [x(α')] is logically





equivalent to [c1(α')]. In other words, a [let] constraint acts like a





macro definition: every use of the variable [x] in the scope of this





definition is equivalent to a copy of the constraint abstraction [c1].









@ 332,21 +332,54 @@ module Make





it can be passed as an argument to {!solve}. *)





val let0: 'a co > (tyvars * 'a) co










(* [letr1 alphas x (fun alphavs v > c1) c2] binds the scheme variable [x]





to the constraint abstraction [fun v > c1] in the contstraint [c2],





where [c1] is also abstracted over a list of rigid variables, one for





each client type variable passed in the list [alphas]. *)





val letr1: int





> tevar





> (variables > variable > 'a co)





> 'b co





> (tyvars * scheme * 'a * 'b) co










val letrn: int





> tevars





> (variables > variables > 'a co)





> 'b co





> (tyvars * schemes * 'a * 'b) co





(**[letr1] is a more general form of the combinator {!let1}. It takes an





integer parameter [k] and binds [k] rigid type variables [βs] in the





lefthand constraint. Like [let1], it also binds a type variable [α]





in the lefthand constraint. Thus, [c1] is a function of [βs] and [α]





to a constraint. On paper, we write [let x = Rβs.λα.c1(βs)(α) in c2].










This constraint requires [∀βs.∃α.c1(α)] to be satisfied.





This is required even if the term variable [x] is not used in [c2].





Thus, the variables [βs] are regarded as rigid while [c1] is solved.










Then, while solving [c2], the term variable [x] is bound to





the constraint abstraction [λα.∃βs.c1(βs)(α)].





In other words, inside [c2], an instantiation constraint of the form





[x(α')] is logically equivalent to [∃βs.c1(βs)(α')].





At this stage, the variables [βs] are no longer treated as rigid,





and can be instantiated.










The combinator [letr1] helps deal with programming language constructs





where one or more rigid variables are explicitly introduced, such as





[let id (type a) (x : a) : a = x in id 0] in OCaml. In this example,





the type variable [a] must be treated as rigid while typechecking the





lefthand side; then, the term variable [id] must receive the scheme





[∀a.a → a], where [a] is no longer regarded as rigid, so this scheme





can be instantiated to [int → int] while typechecking the righthand





side. *)





val letr1:





(* k: *) int >





(* x: *) tevar >





(* c1: *) (variables > variable > 'a co) >





(* c2: *) 'b co >





(tyvars * scheme * 'a * 'b) co










(**[letrn] subsumes {!let1}, {!letr1}, and {!letrn}.










Like {!letr1}, it takes an integer parameter [k] and binds [k]





rigid type variables [βs] in the lefthand constraint.










Like {!letn}, it takes a list [xs] of term variables and binds a





corresponding list [αs] of type variables in the lefthand constraint.










On paper, we write [let xs = Rβs.λαs.c1(βs)(αs) in c2] for the





constraint that it constructs. *)





val letrn:





(* k: *) int >





(* xs: *) tevars >





(* c1: *) (variables > variables > 'a co) >





(* c2: *) 'b co >





(tyvars * schemes * 'a * 'b) co










(*  *)









@ 360,8 +393,9 @@ module Make





(**The constraint [correlate range c] is equivalent to [c], but records that





this constraint is correlated with the range [range] in the source code.





This information is used in error reports. The exceptions {!Unbound},





{!Unify}, and {!Cycle} carry a range: it is the nearest range that





encloses the abstract syntax tree node where the error is detected. *)





{!Unify}, {!Cycle}, and {!VariableScopeEscape} carry a range: it is the





nearest range that encloses the abstract syntax tree node where the error





is detected. *)





val correlate: range > 'a co > 'a co










(** {2 Solving Constraints} *)




