Reputation: 65
TL;DR - In OCaml, how to call the type looks like type 'elt set = (module BatSet.S with type elt = 'elt)
and how to make a value of this type?
Currently, I'm reading code in the Tezos protocol[*], and I saw the following code.
module type Boxed_set = sig
type elt
val elt_ty : elt comparable_ty
module OPS : S.SET with type elt = elt
val boxed : OPS.t
val size : int
end
type 'elt set = (module Boxed_set with type elt = 'elt)
I've never heard about the syntax like type a = (module B)
. So I open a top-level OCaml interpreter and reproduce similar usage using the module batteries. Following code is the log of what I reproduced.
$ ocaml
OCaml version 4.07.1
# #use "topfind";;
- : unit = ()
Findlib has been successfully loaded. Additional directives:
#require "package";; to load a package
#list;; to list the available packages
#camlp4o;; to load camlp4 (standard syntax)
#camlp4r;; to load camlp4 (revised syntax)
#predicates "p,q,...";; to set these predicates
Topfind.reset();; to force that packages will be reloaded
#thread;; to enable threads
- : unit = ()
# #require "batteries";;
[...]: loaded
# type 'elt set = (module BatSet.S with type elt = 'elt);;
type 'elt set = (module BatSet.S with type elt = 'elt)
This weird type-definition really works, but I stuck here. How the module itself can be a type? How to make a value which has type 'elt set
like let v : int set = (...)
? Is there any kind of keyword to call the types like this?
[*] https://gitlab.com/tezos/tezos/blob/master/src/proto_alpha/lib_protocol/script_typed_ir.ml, Commit-Hash: 86b5227f7efd8aa78fcc427776920480c6c0e780
Upvotes: 1
Views: 589
Reputation: 66823
A type like (module M)
is the type of a first-class module.
You can make a value of such a type simply by defining a module with the right type.
Here is a simple example I used to test this out:
# module type B = sig type elt end;;
module type B = sig type elt end
# type 'elt b = (module B with type elt = 'elt);;
type 'elt b = (module B with type elt = 'elt)
# module X = struct type elt = int end;;
module X : sig type elt = int end
# (module X : B with type elt = int);;
- : (module B with type elt = int) = <module>
This last line shows module X
treated as a value (a first-class module).
Now, indeed, this value has type int b
:
# ((module X : B with type elt = int) : int b);;
- : (module B with type elt = int) = <module>
Upvotes: 3
Reputation: 18912
This is the type of a first class module with constraint: https://caml.inria.fr/pub/docs/manual-ocaml/manual028.html .
This type can be used to pack a module inside a value:
let int_set = ((module BatSet.Make(Int)): int set);;
Such values can be then unpacked to a module, for instance, I can use it to define an unique_sorted
function:
let unique_sorted (type a) ((module MySet): a set) list =
let set = List.fold_left (fun set x -> MySet.add x set) MySet.empty list in
MySet.elements set
let test = assert( unique_sorted int_set [4;0;1;2;2] = [0;1;2;4] )
Upvotes: 5