Locally abstract types scope over the definition body where they can be used as type names or to refine GADTs by pattern-matching. module type Ty = sig type t end (* we need the scoping of the locally abstract type in this example; note that (type a) would work as well *) let mkTy : type a . unit -> (module Ty with type t = a) = fun () -> let module T = struct type t = a end in (module T) > val mkTy : unit -> (module Ty with type t = 'a) = (* a type variable 'a only scopes over the type annotation *) let mkTy : 'a . unit -> (module Ty with type t = 'a) = fun () -> let module T = struct type t = 'a end in (module T) > let module T = struct type t = 'a end in > ^^ > Error: Unbound type parameter 'a type _ tag = Int : int tag | Prod : 'a tag * 'b tag -> ('a * 'b) tag (* we need the ability to be refined by GADT matching here *) let rec default : type a . a tag -> a = function | Int -> 0 | Prod (ta, tb) -> (default ta, default tb) > val default : 'a tag -> 'a = (* a type variable just unifies with the first case and fails on the second *) let rec default : 'a . 'a tag -> 'a = function | Int -> 0 | Prod (ta, tb) -> (default ta, default tb) > ^^^^^^^^^^^^^ > Error: This pattern matches values of type ($0 * $1) tag > but a pattern was expected which matches values of type int tag > Type $0 * $1 is not compatible with type int (* the difference by "(type a) ..." and "type a . ..." is that the latter allows polymorphic recursion (just as "'a . ..."), so this example fails with just (type a) *) let rec default (type a) : a tag -> a = function | Int -> 0 | Prod (ta, tb) -> (default ta, default tb) > ^^ > Error: This expression has type $0 tag but an expression > was expected of type 'a > The type constructor $0 would escape its scope On Mon, Mar 28, 2016 at 6:20 AM, Gregory Malecha wrote: > Thanks. I'm not sure I understand the difference between the two though. Is > there an example showing when they produce different results? > > On Sun, Mar 27, 2016 at 6:12 PM, Jacques Garrigue > wrote: >> >> On 2016/03/28 03:52, Gregory Malecha wrote: >> > >> > Thanks, Leo -- >> > >> > This is exactly what I needed to know. I thought that the (type a) >> > annotation was forcing the function to be polymorphic. For future reference, >> > is there any way to write the annotation (that forces the function to be >> > polymorphic) without having to write explicit ‘fun's? >> >> You should either write >> >> let generic_search_stream : ‘b. int option -> (internal_result, ‘b) >> result_stream = … >> >> or >> >> let generic_search_stream : type b. int option -> (internal_result, b) >> result_stream = … >> >> where the latter one both requires polymorphism and defines a locally >> abstract type, >> i.e. probably the behavior you expect with (type b). >> >> Jacques >> > > > > -- > gregory malecha