Locally abstract type with inline record pattern

A relatively recent edition to the language (I can’t seem to find which version) is locally abstract types in pattern matching.

This looks something like:

type _ spec =
  | Int : int spec
  | String : string spec
  
type t0 = T0 : 'a spec * 'a -> t0
  
let f0 = function
  | T0 (type a) ((spec, v) : a spec * a) -> ()

Is it possible to use this syntax/feature with inline record arguments? The following doesn’t work:

type t1 = T1 : { spec : 'a spec; value : 'a } -> t1
  
let f1 = function
  | T1 (type a) { spec : a spec; value : a } -> ()
Error: Existential types introduced in a constructor pattern
must be bound by a type constraint on the argument.

I recognize that the first example also doesn’t work if you annotate the individual elements of the tuple, but there’s no separate type I can reference here.

I could obviously separate out the record into its own type and annotate t1 with [@@unboxed], but was curious if it was possible without doing this.

Hi @zbaylin,

I don’t have an answer to your question, but I’ve encountered a similar situation and found some useful information in this discussion.

Before the current syntax existed, one workaround was to introduce the type in an anonymous fun expression and apply it immediately. This approach still works:

# let f1 = function
    | T1 { spec; value } ->
        (fun (type a) (spec : a spec) (value : a) -> ()) spec value
val f1 : t1 -> unit = <fun>

Perhaps you’d find this more appealing than separating the record in your example?

I’m also interested in learning about other possible approaches to this issue. Thanks for posting the question!

1 Like