Building a record works like this: let's say you have a record 'r
which has n fields of types 'f1
, ..., 'fn
.
First you call record ~create
, supplying a create function of type 'f1 -> ... -> 'fn -> 'r
. In most cases, your create function can delegate to Fields.create
as in the usage example below.
This gives you a ('r, 'f1 -> ... -> 'fn -> 'r) Record_builder.t
. The first type parameter 'r
is a phantom type which exists only for additional type safety.
You turn this into a ('r, 'r) Record_builder.t
by applying the <.*> operator once for each field, in order. First, you call it with a ('r, 'f1) Record_field.t
to get a ('r, 'f2 -> .. -> 'fn -> 'r) Record_builder.t
, then with a ('r, 'f2) Record_field.t
to get a ('r, 'f3 -> ... -> 'fn -> 'r) Record_builder.t
, and so on until you end up with a ('r, 'r) Record_builder.t
. You can obtain a Record_field.t
using the field
function.
Finally you convert your ('r, 'r) Record_field.t
into a 'r Sexp_form.t
using finish_record
.
Usage example:
module Foo = struct
type t =
{ a : string
; b : int
}
[@@deriving fields, sexp_of]
end
let foo : Foo.t Sexp_form.t =
let open Sexp_form.Primitives in
let module Fields = Foo.Fields in
record ~create:(fun a b -> Fields.create ~a ~b)
<.*> field (string ()) Fields.a
<.*> field int Fields.b
|> finish_record