This extension provides two features:
- Generate
Accessor
isomorphisms, fields, variants, and optionals from types. - Eta expand
Accessor
-defining expressions to avoid the value restriction.
Syntax
- Type definitions
[@@deriving accessors]
- Expressions
[%accessor EXPR]
Usage
Polymorphizing accessors
Wrap an expression defining an accessor like this:
[%accessor Accessor.field ~get ~set]
This causes the expression to be as polymorphic as possible via eta expansion. The generated code in the above example would be something like this:
{ Accessor.f =
(fun selector mapping ->
(Accessor.field ~get ~set).f selector mapping)
}
Deriving accessors
Annotate a type definition like this:
type t =
{ foo : int
; bar : string
}
[@@deriving accessors]
This generates different accessors depending on the type definition.
You can optionally specify to generate the accessors in a submodule, like this:
type t =
{ foo : int
; bar : string
}
[@@deriving accessors ~submodule:My_submodule]
This can be useful to avoid name clashes with [@@deriving fields]
. If you
want to derive both accessors
and fields
, you have three options, but
only two are useful:
- Derive accessors before fields
[@@deriving accessors, fields]
The getter functions generated byfields
will shadow the accessors, so there is little point in this arrangement.- Derive fields before accessors
[@@deriving fields, accessors]
The accessors will shadow the getter functions generated byfields
, but you still get theFields
module.- Provide a submodule for accessors values
[@@deriving accessors ~submodule:Some_submodule, fields]
Nothing will be shadowed, but the accessors will be stuffed into a submodule, which makes using them more verbose.
Records
ppx_accessor
generates one accessor per record field.
Multiple fields
Records with multiple fields result in field
accessors.
type t =
{ foo : int
; bar : string
}
[@@deriving accessors]
For the above type, these accessors would be generated:
let foo =
[%accessor Accessor.field ~get:(fun t -> t.foo) ~set:(fun t foo -> { t with foo })
let bar =
[%accessor Accessor.field ~get:(fun t -> t.bar) ~set:(fun t bar -> { t with bar })
One field
Records with one field result in an isomorphism
accessor.
type t = { foo : int } [@@deriving accessors]
For the above type, this accessor would be generated:
let foo =
[%accessor
Accessor.isomorphism ~get:(fun t -> t.foo) ~construct:(fun foo -> { foo })
Variants
ppx_accessor
generates one accessor per constructor that doesn’t use inline
record syntax. Inline records result in a submodule named after the
constructor which contains one accessor per field of the inline record.
Multiple constructors
Variants with multiple constructors result in variant
and optional
accessors.
type t =
| Foo
| Bar of int * string
| Baz of { a : float }
| Quux of { a : int; b : string }
[@@deriving accessors]
For the above type, these accessors would be generated:
let foo =
[%accessor
Accessor.variant
~match_:(function
| Foo -> First ()
| (Bar _ | Baz _ | Quux _) as r -> Second r)
~construct:(fun () -> Foo)]
let bar =
[%accessor
Accessor.variant
~match_:(function
| Bar (x, y) -> First (x, y)
| (Foo | Baz _ | Quux _) as r -> Second r)
~construct:(fun (x, y) -> Bar (x, y)]
module Baz = struct
let a =
[%accessor
Accessor.variant
~match_:(function
| Baz t -> First t.a
| (Foo | Bar _ | Quux _) as r -> Second r)
~construct:(fun a -> Baz { a })]
end
module Quux = struct
let a =
[%accessor
Accessor.optional
~match_:(function
| Quux t -> First t.a
| (Foo | Bar _ | Baz _) as r -> Second r)
~set:(fun t a ->
match t with
| Quux t -> Quux { t with a }
| (Foo | Bar _ | Baz _) as r -> r)]
let b =
[%accessor
Accessor.optional
~match_:(function
| Quux t -> First t.b
| (Foo | Bar _ | Baz _) as r -> Second r)
~set:(fun t b ->
match t with
| Quux t -> Quux { t with b }
| (Foo | Bar _ | Baz _) as r -> r)]
end
Single constructors
Variants with one constructor result in either an isomorphism
or field
accessor.
Constructors without inline record syntax
A singleton variant that does not use inline record syntax results in an isomorphism.
type t = Foo of int [@@deriving accessors]
For the above type, this accessor would be generated:
let foo =
[%accessor Accessor.isomorphism ~get:(fun (Foo n) -> n) ~construct:(fun n -> Foo n)]
Constructors with inline record syntax
A singleton variant using inline record syntax is treated like a normal record, but the accessors live in a submodule named after the constructor.
Multiple fields
Records with multiple fields result in field
accessors.
type t =
Foo of
{ foo : int
; bar : string
}
[@@deriving accessors]
For the above type, these accessors would be generated:
module Foo = struct
let foo =
[%accessor
Accessor.field
~get:(fun (Foo t) -> t.foo)
~set:(fun (Foo t) foo -> Foo { t with foo })
let bar =
[%accessor
Accessor.field
~get:(fun (Foo t) -> t.bar)
~set:(fun (Foo t) bar -> Foo { t with bar })
end
One field
Records with one field result in an isomorphism
accessor.
type t = A of { foo : int } [@@deriving accessors]
For the above type, this accessor would be generated:
module A = struct
let foo =
[%accessor
Accessor.isomorphism
~get:(fun (A t) -> t.foo)
~construct:(fun foo -> A { foo })
end
Polymorphic variants
ppx_accessor
generates one variant
accessor per constructor in a
polymorphic variant. If there is only one constructor, it generates an
isomorphism
instead. If the type definition inherits from another
polymorphic variant, it generates a variant
accessor for converting to and
from the inherited type.