This extension provides two features:
- Generate
Accessorisomorphisms, fields, variants, and optionals from types. - Eta expand
Accessor-defining expressions to avoid the value restriction.
- Type definitions
[@@deriving accessors]- Expressions
[%accessor EXPR]
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)
}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 byfieldswill 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 theFieldsmodule.- 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.
ppx_accessor generates one accessor per record field.
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 })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 })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.
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)]
endVariants with one constructor result in either an isomorphism or field
accessor.
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)]A singleton variant using inline record syntax is treated like a normal record, but the accessors live in a submodule named after the constructor.
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 })
endRecords 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 })
endppx_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.