https://github.com/janestreet/ppx_enumerate
Generate a list containing all values of a finite type
https://github.com/janestreet/ppx_enumerate
Last synced: 9 months ago
JSON representation
Generate a list containing all values of a finite type
- Host: GitHub
- URL: https://github.com/janestreet/ppx_enumerate
- Owner: janestreet
- License: mit
- Created: 2015-09-25T17:02:51.000Z (over 10 years ago)
- Default Branch: master
- Last Pushed: 2025-04-28T18:35:16.000Z (9 months ago)
- Last Synced: 2025-04-28T19:38:25.245Z (9 months ago)
- Language: OCaml
- Size: 125 KB
- Stars: 26
- Watchers: 8
- Forks: 4
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGES.md
- Contributing: CONTRIBUTING.md
- License: LICENSE.md
Awesome Lists containing this project
- awesome-list - ppx_enumerate
README
ppx_enumerate
=============
Generate a list containing all values of a finite type.
`ppx_enumerate` is a ppx rewriter which generates a definition for the
list of all values of a type with (for a type which only has finitely
many values).
Basic Usage
-----------
The basic usage is simply to add "[@@deriving enumerate]" after the type
definition. For example:
```ocaml
type t =
| Foo
| Bar of bool
| Baz of [`A | `B of unit option]
[@@deriving enumerate]
```
will produce a value `val all : t list`, whose value is equal to
```ocaml
[ Foo; Bar true; Bar false; Baz `A; Baz (`B None); Baz (`B Some ()) ]
```
in some order (that is, there is no guarantee about the order of the list).
Polymorphic types
-----------------
In a similar fashion as sexplib, using '[@@deriving enumerate]' on polymorphic
types produces a function for [all]. For example,
```ocaml
type 'a t =
| Foo
| Bar of 'a option
[@@deriving enumerate]
```
will produce a value `val all : 'a list -> 'a t list`, whose value is
semantically equal to
```ocaml
fun all_of_a -> Foo :: Bar None :: List.map all_of_a ~f:(fun x -> Bar (Some x))
```
Types not named `t`
-------------------
If the type is not named `t`, then the enumeration is called
`all_of_` instead of `all`.
Records and Tuples
------------------
Product types are supported as well as sum types. For example,
```ocaml
type t =
{ foo : [`A | `B]
; bar : [`C | `D]
} [@@deriving enumerate]
```
produces a `val all : t list` whose value is equal (up to order) to:
```ocaml
[ { foo = `A; bar = `C }; { foo = `A; bar = `D };
{ foo = `B; bar = `C }; { foo = `B; bar = `D };
]
```
Tuples and variants with multiple arguments are similarly supported.
Overriding the `all` value
---------------------------
Just like with sexplib, it can sometimes be useful to provide a custom
value of `all`. For example, you might define a type of bounded
integers:
```ocaml
module Small_int : sig
type t = private int [@@deriving enumerate]
val create_exn : int -> t
end = struct
type t = int
let limit = 100
let create_exn i = if i < 0 || i >= limit then failwith "out of bounds"; i
let all = List.init limit ~f:(fun i -> i)
end
```
You could then use `Small_int.t` as normal with other types using
`[@@deriving enumerate]`:
```ocaml
type t =
| Foo
| Bar of Small_int.t option
[@@deriving enumerate]
```
Custom attribute
----------------
You can also override `all` for a type within a type definition using the
`[@enumerate.custom]` attribute:
```ocaml
type t =
| Foo
| Bar of (string[@enumerate.custom [ "baz"; "qux" ]]) * bool
```
This can be useful in cases where you want to use `enumerate` to help exercise different
codepaths based on which case you're in, but the contents are not enumerable. For example,
your code may have different control flow based on whether a `string option` is `Some str`
or `None`, but not have material changes based on the value of `str`, in which case you
could use `(string [@enumerate.custom [ "example" ]]) option`.
Using `all` without defining a type name
----------------------------------------
You don't have to define a type name to be able to create the list of
values of a type. You do it for any type expression by using the `all`
quotation. For example:
```ocaml
[%all: bool * bool]
```
which will evaluate to:
```ocaml
[ (true, true); (true, false); (false, false); (false, true) ]
```
Known issues
------------
Using `all` for polymorphic variants with duplicated constructors leads
to duplicate values in the resulting lists:
```ocaml
type t = [ `A ] [@@deriving enumerate]
let () = assert ([%all: [ t | t ] ] = [ `A; `A ])
```