package ppx_accessor

  1. Overview
  2. Docs
[@@deriving] plugin to generate accessors for use with the Accessor libraries

Install

Dune Dependency

Authors

Maintainers

Sources

ppx_accessor-v0.15.0.tar.gz
sha256=1c296a857b58361c745f346337e738d6c7eb4376a5950208d796c61189ba2ea6

Description

Automatically generate accessors given a type definition.

Published: 21 Mar 2022

README

README.org

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:

   #+BEGIN_SRC ocaml
     [%accessor Accessor.field ~get ~set]
   #+END_SRC

   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:

   #+BEGIN_SRC ocaml
     { Accessor.f =
         (fun selector mapping ->
           (Accessor.field ~get ~set).f selector mapping)
     }
   #+END_SRC

** Deriving accessors

   Annotate a type definition like this:

   #+BEGIN_SRC ocaml
     type t =
       { foo : int
       ; bar : string
       }
     [@@deriving accessors]
   #+END_SRC

   This generates different accessors depending on the type definition.

   You can optionally specify to generate the accessors in a submodule, like this:

   #+BEGIN_SRC ocaml
     type t =
       { foo : int
       ; bar : string
       }
     [@@deriving accessors ~submodule:My_submodule]
   #+END_SRC

   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 by ~fields~ 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 by ~fields~, but
        you still get the ~Fields~ 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.

     #+BEGIN_SRC ocaml
       type t =
         { foo : int
         ; bar : string
         }
       [@@deriving accessors]
     #+END_SRC

     For the above type, these accessors would be generated:

     #+BEGIN_SRC ocaml
       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 })
     #+END_SRC

**** One field

     Records with one field result in an ~isomorphism~ accessor.

     #+BEGIN_SRC ocaml
       type t = { foo : int } [@@deriving accessors]
     #+END_SRC

     For the above type, this accessor would be generated:

     #+BEGIN_SRC ocaml
       let foo =
         [%accessor
             Accessor.isomorphism ~get:(fun t -> t.foo) ~construct:(fun foo -> { foo })
     #+END_SRC

*** 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.

     #+BEGIN_SRC ocaml
       type t =
         | Foo
         | Bar of int * string
         | Baz of { a : float }
         | Quux of { a : int; b : string }
       [@@deriving accessors]
     #+END_SRC

     For the above type, these accessors would be generated:

     #+BEGIN_SRC ocaml
       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
     #+END_SRC

**** 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.

      #+BEGIN_SRC ocaml
      type t = Foo of int [@@deriving accessors]
      #+END_SRC

      For the above type, this accessor would be generated:

      #+BEGIN_SRC ocaml
      let foo =
        [%accessor Accessor.isomorphism ~get:(fun (Foo n) -> n) ~construct:(fun n -> Foo n)]
      #+END_SRC

***** 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.

       #+BEGIN_SRC ocaml
         type t =
           Foo of
             { foo : int
             ; bar : string
             }
         [@@deriving accessors]
       #+END_SRC

       For the above type, these accessors would be generated:

       #+BEGIN_SRC ocaml
         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
       #+END_SRC

****** One field

       Records with one field result in an ~isomorphism~ accessor.

       #+BEGIN_SRC ocaml
         type t = A of { foo : int } [@@deriving accessors]
       #+END_SRC

       For the above type, this accessor would be generated:

       #+BEGIN_SRC ocaml
         module A = struct
           let foo =
             [%accessor
                 Accessor.isomorphism
                   ~get:(fun (A t) -> t.foo)
                   ~construct:(fun foo -> A { foo })
         end
       #+END_SRC

*** 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.

Dependencies (5)

  1. ppxlib >= "0.23.0"
  2. dune >= "2.0.0"
  3. base >= "v0.15" & < "v0.16"
  4. accessor >= "v0.15" & < "v0.16"
  5. ocaml >= "4.09.0" & < "5.1"

Dev Dependencies

None

Used by (3)

  1. accessor_async = "v0.15.0"
  2. accessor_base = "v0.15.0"
  3. accessor_core = "v0.15.0"

Conflicts

None