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
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 *)
It’s totally unlikely that you need to do this, but it’s a funny request
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
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