Skip to content
Generation of accessor and iteration functions for ocaml variant types
OCaml Makefile
Branch: master
Clone or download
Latest commit f474f16 Oct 15, 2019
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
example v0.12-preview.120.19+118 Jan 17, 2019
src v0.13-preview.120.49+223 Aug 19, 2019
test v0.13-preview.121.07+168 Oct 15, 2019
.gitignore v0.13-preview.120.27+112 Mar 14, 2019
CHANGES.md v0.11.117.06+24 May 10, 2018
CONTRIBUTING.md v0.11.120.08+153 Nov 6, 2018
LICENSE.md v0.12-preview.120.18+252 Jan 16, 2019
Makefile v0.12-preview.120.18+252 Jan 16, 2019
README.md v0.11.117.17+10 Aug 7, 2018
dune v0.12-preview.120.18+252 Jan 16, 2019
dune-project v0.12-preview.120.18+252 Jan 16, 2019
ppx_variants_conv.opam v0.13-preview.120.49+223 Aug 19, 2019

README.md

ppx_variants_conv

Generation of accessor and iteration functions for ocaml variant types.

ppx_variants_conv is a ppx rewriter that can be used to define first class values representing variant constructors, and additional routines to fold, iterate and map over all constructors of a variant type.

It provides corresponding functionality for variant types as ppx_fields_conv provides for record types.

Basic use of [@@deriving variants] and variantslib

This code:

type 'a t =
  | A of 'a
  | B of char
  | C
  | D of int * int
  [@@deriving variants]

generates the following values:

(** first-class constructor functions *)
val a : 'a -> 'a t
val b : char -> 'a t
val c : 'a t
val d : int -> int -> 'a t

(** higher order variants and functions over all variants *)
module Variants : sig
  val a : ('a -> 'a t)         Variant.t
  val b : (char -> 'a t)       Variant.t
  val c : ('a t)               Variant.t
  val d : (int -> int -> 'a t) Variant.t

  val fold :
    init: 'b
    -> a:('b -> ('a -> 'a t)         Variant.t -> 'c)
    -> b:('c -> (char -> 'a t)       Variant.t -> 'd)
    -> c:('d -> ('a t)               Variant.t -> 'e)
    -> d:('e -> (int -> int -> 'a t) Variant.t -> 'f)
    -> 'f

  val iter :
       a: (('a -> 'a t)         Variant.t -> unit)
    -> b: ((char -> 'a t)       Variant.t -> unit)
    -> c: (('a t)               Variant.t -> unit)
    -> d: ((int -> int -> 'a t) Variant.t -> unit)
    -> unit

  val map :
    'a t
    -> a: (('a -> 'a t)         Variant.t -> 'a                 -> 'r)
    -> b: ((char -> 'a t)       Variant.t -> char               -> 'r)
    -> c: (('a t)               Variant.t                       -> 'r)
    -> d: ((int -> int -> 'a t) Variant.t -> int -> int -> 'a t -> 'r)
    -> 'r

  val make_matcher :
       a:(('a -> 'a t)         Variant.t -> 'b -> ('c -> 'd)         * 'e)
    -> b:((char -> 'f t)       Variant.t -> 'e -> (char -> 'd)       * 'g)
    -> c:('h t                 Variant.t -> 'g -> (unit -> 'd)       * 'i)
    -> d:((int -> int -> 'j t) Variant.t -> 'i -> (int -> int -> 'd) * 'k)
    -> 'b
    -> ('c t -> 'd) * 'k

  val to_rank : _ t -> int
  val to_name : _ t -> string

  (** name * number of arguments, ie [("A", 1); ("B", 1); ("C", 0); ("D", 2)]. *)
  val descriptions : (string * int) list
end

Variant.t is defined in Variantslib as follows:

module Variant = struct
  type 'constructor t = {
    name : string;
    (* the position of the constructor in the type definition, starting from 0 *)
    rank : int;
    constructor : 'constructor
  }
end

The fold, iter, and map functions are useful in dealing with the totality of variants. For example, to get a list of all variants when all the constructors are nullary:

type t =
  | First
  | Second
  | Third
  [@@deriving variants]
let all =
  let add acc var = var.Variantslib.Variant.constructor :: acc in
  Variants.fold ~init:[]
    ~first:add
    ~second:add
    ~third:add

Just like with [@@deriving fields], if the type changes, the compiler will complain until this definition is updated as well.

ppx_variant_libs works similarly on simple polymorphic variants (without row variables and without inclusion).

You can’t perform that action at this time.