ppx_irmin
PPX extension for automatically generating Irmin generics.
Overview
ppx_irmin automatically generates Irmin generics (values of type _ Irmin.Type.t) corresponding to type declarations in your code. For example:
type tree =
  | Branch of tree * bool option * tree
  | Leaf of int32 * string [@@deriving irmin]
will be expanded to:
type tree = (* as above *)
let tree_t =
  let open Irmin.Type in
  mu (fun tree_t ->
      variant "tree" (fun branch leaf -> function
          | Branch (x1, x2, x3) -> branch (x1, x2, x3)
          | Leaf   (x1, x2)     -> leaf (x1, x2))
      |~ case1 "Branch" (triple tree_t (option bool) tree_t) (fun (x1, x2, x3) -> Branch (x1, x2, x3))
      |~ case1 "Leaf"   (pair int32 string)                  (fun (x1, x2) -> Leaf (x1, x2))
      |> sealv)
Installation and usage
ppx_irmin may be installed via opam:
opam install ppx_irmin
If you're using the dune build system, add the following field to your library, executable or test stanza:
(preprocess (pps ppx_irmin))
You can now use [@@deriving irmin] after a type declaration in your code to automatically derive an Irmin generic with the same name.
Specifics
ppx_irmin supports all of the type combinators exposed in the Irmin.Type module (basic types, records, variants (plain and closed polymorphic), recursive types etc.). Irmin does not currently support higher-kinded generics: all Irmin types must fully grounded (no polymorphic type variables).
To supply base representations from a module other than Irmin.Type (such as when Irmin.Type is aliased to a different module path), the lib argument can be passed to @@deriving irmin:
type foo = unit [@@deriving irmin { lib = Some "Mylib.Types" }]
(* generates the value *)
val foo_t = Mylib.Types.unit
Naming scheme
The generated generics will be called <type-name>_t, unless the type-name is t, in which case the generic is simply t. This behaviour can be overridden using the name argument, as in:
type foo = string list * int32 [@@deriving irmin { name = "foo_generic" }]
(* generates the value *)
val foo_generic = Irmin.Type.(pair (list string) int32)
If the type contains an abstract type, ppx_irmin will expect to find a corresponding generic using its own naming rules. This can be overridden using the [@generic ...] attribute, as in:
type bar = (foo [@generic foo_generic], string) result [@@deriving irmin]
(* generates the value *)
val bar_t = Irmin.Type.(result foo_generic string)
Built-in abstract types such as unit are assumed to be represented in Irmin.Type. This behaviour can be overridden with the [@nobuiltin] attribute:
type t = unit [@nobuiltin] [@@deriving irmin]
(* generates the value *)
let t = unit_t (* not [Irmin.Type.unit] *)
Signature type definitions
The ppx_irmin deriver can also be used in signatures to expose the auto-generated value:
module Contents : sig
  type t = int32 [@@deriving irmin]
  (* exposes generic in signature *)
  val t : t Irmin.Type.t
end = struct
  type t = int32 [@@deriving irmin]
  (* generates generic value *)
  val t = Irmin.Type.int32
end