Access inferred types

Given type:

type ('a, 'b) my_type = { a : 'a; b : 'b }

we can create a value:

let my_t : (_, _) my_type = { a = 5; b = false }

OCaml automatically infers its type as (int, bool) my_type. Is there any way to access that type?
To say something like type my_t = typeof my_t, which results in type my_t = (int, bool) my_type?

And is there any way, given my_t to create a type with whatever the inferred type for a or b is?
Almost like a function of types, that takes the inferred type of my_t as an input and outputs int for a or bool for b

For example (this syntax doesn’t exists):

type a_type = ('a, 'b) my_type -> 'a
type a = a_type (typeof my_t)
(* -> type a is int *)

It’s totally unlikely that you need to do this, but it’s a funny request :stuck_out_tongue:
Types always live inside modules in OCaml, so we can only produce them as the output of a function by wrapping them in a first-class module:

module type S = sig type t end

let typeof (type a) (_ : a) =
  (module struct type t = a end : S with type t = a)

type ('a, 'b) my_type = { a : 'a; b : 'b }
let my_t = { a = 5 ; b = false }
module Test = (val typeof my_t)
(* type Test.t = (int, bool) my_type *)

You can also do “function types” to extract the type arguments: (again, by packaging the types inside modules)

let a_type (type a) (module _ : S with type t = (a, _) my_type) = 
  (module struct type t = a end : S with type t = a)

module A = (val a_type (typeof my_t))
(* type A.t is int *)
7 Likes

This is beautiful, thank you!

It’s totally unlikely that you need to do this, but it’s a funny request :stuck_out_tongue:

I wanted to reduce some of the boilerplate of typing types by inferring them from functions. I’m not sure I truly need this either

With this, I can create a module interface like so:

module type T = sig
  module M : module type of (val a_type (typeof my_t))

  type my_a = M.t

  val a : my_a
end

module My_t : T = struct
  module M = struct
    type t = int
  end

  type my_a = int

  let a = 5
end

But is there a special syntax to skip the whole module M creation, so that it doesn’t pollute module type T ? Is there some special syntax to inline everything?
I was hoping there’s something like:

  type my_a2 = (module type of (val a_type (typeof my_t))).t

but that’s not valid syntax

There’s no such syntax indeed (probably for profound reasons since computations are generally unavailable in type expressions, with no special cases for when it’s easy and safe to accept them).

You can however use include for a similar outcome:

module type T = sig
  include module type of (val a_type (typeof my_t))
  val a : t
end

(* or rename the type on the fly: *)
module type for_educational_purposes_only = sig
  include module type of (
    (functor (X:S) -> struct type my_a = X.t end)
      (val a_type (typeof my_t))
  )
  val a : my_a
end
2 Likes

nice, thank you so very much (I needed the renaming part as well)

It ended up being more complicated than just typing the type, but I learned a lot about the modules, types :eyes: