


@ 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} *) 



