Legend:
Library
Module
Module type
Parameter
Class
Class type
Yet-an-other type combinator library
Type provides type combinators to define runtime representation for OCaml types and generic operations to manipulate values with a runtime type representation.
The type combinators supports all the usual type primitives but also compact definitions of records and variants. It also allows the definition of run-time representations of recursive types.
Type Combinators
type'a t
The type for runtime representation of values of type 'a.
type len = [
| `Int
| `Int8
| `Int16
| `Int32
| `Int64
| `Fixed of int
]
The type of integer used to store buffers, list or array lengths.
result a b is a representation of values of type (a, b) result.
Records
type('a, 'b, 'c) open_record
The type for representing open records of type 'a with a constructor of type 'b. 'c represents the remaining fields to be described using the (|+) operator. An open record initially satisfies 'c = 'b and can be sealed once 'c = 'a.
record n f is an incomplete representation of the record called n of type 'a with constructor f. To complete the representation, add fields with (|+) and then seal the record with sealr.
type('a, 'b) field
The type for fields holding values of type 'b and belonging to a record of type 'a.
type menu = { restaurant : string; items : (string * int32) list }
let t =
record "t" (fun restaurant items -> { restaurant; items })
|+ field "restaurant" string (fun t -> t.restaurant)
|+ field "items" (list (pair string int32)) (fun t -> t.items)
|> sealr
Variants
type('a, 'b, 'c) open_variant
The type for representing open variants of type 'a with pattern matching of type 'b. 'c represents the remaining constructors to be described using the (|~) operator. An open variant initially satisfies c' = 'b and can be sealed once 'c = 'a.
val variant : string ->'b->('a, 'b, 'b)open_variant
variant n p is an incomplete representation of the variant type called n of type 'a using p to deconstruct values. To complete the representation, add cases with (|~) and then seal the variant with sealv.
type('a, 'b) case
The type for representing variant cases of type 'a with patterns of type 'b.
type'a case_p
The type for representing patterns for a variant of type 'a.
type t = Foo | Bar of string
let t =
variant "t" (fun foo bar -> function Foo -> foo | Bar s -> bar s)
|~ case0 "Foo" Foo
|~ case1 "Bar" string (fun x -> Bar x)
|> sealv
enum n cs is a representation of the variant type called n with singleton cases cs. e.g.
type t = Foo | Bar | Toto
let t = enum "t" [ ("Foo", Foo); ("Bar", Bar); ("Toto", Toto) ]
Recursive definitions
Type allows a limited description of recursive records and variants.
TODO: describe the limitations, e.g. only regular recursion and no use of the generics inside the mu* functions and the usual caveats with recursive values (such as infinite loops on most of the generics which don't check sharing).
mu2 f is the representations r and s such that r, s = mu2 r s.
For instance:
type r = { foo : int; bar : string list; z : z option }
and z = { x : int; r : r list }
(* Build the representation of [r] knowing [z]'s. *)
let mkr z =
record "r" (fun foo bar z -> { foo; bar; z })
|+ field "foo" int (fun t -> t.foo)
|+ field "bar" (list string) (fun t -> t.bar)
|+ field "z" (option z) (fun t -> t.z)
|> sealr
(* And the representation of [z] knowing [r]'s. *)
let mkz r =
record "z" (fun x r -> { x; r })
|+ field "x" int (fun t -> t.x)
|+ field "r" (list r) (fun t -> t.r)
|> sealr
(* Tie the loop. *)
let r, z = mu2 (fun r z -> (mkr z, mkz y))
Generic Operations
Given a value 'a t, it is possible to define generic operations on value of type 'a such as pretty-printing, parsing and unparsing.
Similar to dump but pretty-prints the JSON representation instead of the OCaml one. See encode_json for details about the encoding.
For instance:
type t = { foo : int option; bar : string list }
let t =
record "r" (fun foo bar -> { foo; bar })
|+ field "foo" (option int) (fun t -> t.foo)
|+ field "bar" (list string) (fun t -> t.bar)
|> sealr
let s = Fmt.strf "%a\n" (pp t) { foo = None; bar = [ "foo" ] }
(* s is "{ foo = None; bar = [\"foo\"]; }" *)
let j = Fmt.strf "%a\n" (pp_json t) { foo = None; bar = [ "foo" ] }
(* j is "{ \"bar\":[\"foo\"] }" *)
NOTE: this will automatically convert JSON fragments to valid JSON objects by adding an enclosing array if necessary.
encode_json t e encodes t into the jsonm encoder e. The encoding is a relatively straightforward translation of the OCaml structure into JSON. The main highlights are:
OCaml ints are translated into JSON floats.
OCaml strings are translated into JSON strings. You must then ensure that the OCaml strings contains only valid UTF-8 characters.
OCaml record fields of type 'a option are automatically unboxed in their JSON representation. If the value if None, the field is removed from the JSON object.
variant cases built using case0 are represented as strings.
variant cases built using case1 are represented as a record with one field; the field name is the name of the variant.
NOTE: this can be used to encode JSON fragments. It's the responsibility of the caller to ensure that the encoded JSON fragment fits properly into a well-formed JSON object.
pre_hash t x is the string representation of x, of type t, which will be used to compute the digest of the value. By default it's to_bin_string t x but it can be overriden by v, like and map operators.
to_bin_string t x use encode_bin to convert x, of type t, to a string.
NOTE: When t is Type.string or Type.bytes, the original buffer x is not prefixed by its size as encode_bin would do. If t is Type.string, the result is x (without copy).
val of_bin_string : 'at->string ->('a, [ `Msg of string ])result
of_bin_string t s is v such that s = to_bin_string t v.
NOTE: When t is Type.string, the result is s (without copy).