Search code examples
typesmoduleocamlfirst-class

Ocaml first-class module and extended variant


I tried to use first-class module by implementing this piece of code :

module Component =
  struct

    type t_data = ..

    module type S =
      sig
        type t
        val create : t -> t_data
      end

    module Make (C: sig type t end) =
      struct
        type t = C.t
        type t_data += T of C.t
        let create data = T data
      end

  end

let create m data =
  let module M = (val m : Component.S) in M.create data

(*  The type constructor M.t would escape its scope *)

I would also try this alternative but I don't know how to add the extended type t_data in the module S :

let create' m data =
  let module M = (val m : Component.S) in M.T data
(* Unbound constructor M.T *)

I'm using bucklescript, thanks !


Solution

  • You just need some extra annotations to convince the typechecker:

    let create (type t0) (m : (module Component.S with type t = t0)) data =
      let module M = (val m) in M.create data
    

    Which can be shorten into:

    let create (type t0) (module M : Component.S with type t = t0) data =
      M.create data
    

    The (type t) annotation introduces a local abstract datatype. Outside the function, this type is turned into a universal type variable, thus given the type:

    val create : (module Component.S with type t = 'a) -> 'a -> Component.t_data
    

    You can use the locally abstract type like any other type, notably you can put it in locally defined modules as well:

    let inject (type t0) data =
      let module M0 = struct type t = t0 end in
      let module M = Component.Make(M0) in
      M.create data
    val make : 'a -> Component.t_data