

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) = <fun>



(* 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 = <fun>



(* 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

Locally abstract types scope over the definition body where they canbe used as type names or to refine GADTs by pattern-matching.On Mon, Mar 28, 2016 at 6:20 AM, Gregory Malecha < gmalecha AT gmail.com > 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> < garrigue AT math.nagoya-u.ac.jp > 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