Module Accessor_base
include Accessor
Types
type ('inner, 'outer, 'kind) t={f : w. ('kind, 'w) Accessor__.Dictionary.t -> ('inner, 'w) Accessor__.Mapping.t -> ('outer, 'w) Accessor__.Mapping.t;}Here is a summary of the type parameters in
(i -> a -> b, it -> at -> bt, c) Accessor.t:iis the output index typeais the type of value that is readbis the type of value that is writtenitis the input index typeatis the type of value that is read frombtis the type of value resulting from a writecis the kind of accessor
The representation is exposed, but not intended to be used directly.
module Simple = Accessor.SimpleAccessors are commonly not indexed and don't need to support polymorphic updates. In such cases, it may be easier to read and write types in terms of
Simple.t. Here is an example where the improvement by usingSimple.tis significant:
module O = Accessor.OTo use
Accessorin your own code, it is recommended to add the following to your import.ml:
type at_least_one=[|`at_least_one]type at_most_one=[|`at_most_one]type coerce=[|`coerce]type construct=[|`construct]type get=[|`get]type map=[|`map]type constructor= constructtype equality=[|get|map|at_most_one|at_least_one|construct|coerce]type field=[|get|map|at_most_one|at_least_one]type getter=[|get|at_least_one|at_most_one]type isomorphism=[|get|map|at_most_one|at_least_one|construct]type many=[|get|map]type many_getter= gettype mapper= maptype nonempty=[|get|map|at_least_one]type nonempty_getter=[|get|at_least_one]type optional=[|get|map|at_most_one]type optional_getter=[|get|at_most_one]type variant=[|get|map|at_most_one|construct]
val (@>) : ('middle, 'outer, 'kind) t -> ('inner, 'middle, 'kind) t -> ('inner, 'outer, 'kind) ta @> bis the composition of the two accessorsaandb. From left to right, a chain of composed accessors goes from outermost to innermost values. The resulting accessor kind is determined by the least powerful argument. Here are a few examples:- An
isomorphismcomposed with afieldis afield. - A
fieldcomposed with avariantis anoptional. - A
gettercomposed with avariantis anoptional_getter.
It's normally more intuitive to think of the operations you need than to think of exactly which kind of accessor you are creating. For example, if you are trying to extract a value from a data structure using a
field, you would probably useget. However, if you compose thefieldwith anoptional,getno longer makes sense; you must use something likeget_option, instead.The non-operator name is
Accessor.compose.- An
val (.@()) : 'at -> (Base.unit -> 'a -> 'b, Base.unit -> 'at -> 'bt, [> getter ]) t -> 'ax.@(t)extracts a single value fromxas identified byt. The non-operator name isAccessor.get.
val (.@?()) : 'at -> (Base.unit -> 'a -> _, Base.unit -> 'at -> _, [> optional_getter ]) t -> 'a Base.optionx.@?(t)extracts at most one value fromxas identified byt. The non-operator name isAccessor.get_option.
val (.@*()) : 'at -> (Base.unit -> 'a -> _, Base.unit -> 'at -> _, [> many_getter ]) t -> 'a Base.listx.@*(t)extracts any number of values fromxas identified byt. The non-operator name isAccessor.to_list.
val id : ('a, 'a, _) tidcan be used as any kind of accessor. It is also the only way to summon anequality.
Using accessors
Indices
module Index = Accessor.IndexAn
Index.tis a heterogeneous stack of values intended to serve as "breadcrumbs" that show how you got to some value currently being accessed inside a composite data structure. For example, if on the way in you traversed aMap.t, one component of the index might be the key of the data being accessed.
module Subtyping = Accessor.SubtypingThe
Subtypingmodule contains all the types used for accessor subtyping. You shouldn't have to use it, but it's here for the documentation.
Functions
Getting and Folding
val get : (Base.unit -> 'a -> _, Base.unit -> 'at -> _, [> getter ]) t -> 'at -> 'aget t atreads a value fromat.
val geti : ('i -> 'a -> _, Base.unit -> 'at -> _, [> getter ]) t -> 'at -> 'i Index.t * 'ageti t atreads a value and its index fromat.
val get_option : (Base.unit -> 'a -> _, Base.unit -> 'at -> _, [> optional_getter ]) t -> 'at -> 'a Base.optionget_option t atreads a value fromat, if present.
val get_optioni : ('i -> 'a -> _, Base.unit -> 'at -> _, [> optional_getter ]) t -> 'at -> ('i Index.t * 'a) Base.optionget_optioni t atreads a value and its index fromat, if present.
val match_ : (Base.unit -> 'a -> _, Base.unit -> 'at -> 'bt, [> variant ]) t -> 'at -> ('a, 'bt) Base.Either.tmatch_ t atis likeget_option, but in the failure case it may be able to give you the input data structure with a different type.
val matchi : ('i -> 'a -> _, Base.unit -> 'at -> 'bt, [> variant ]) t -> 'at -> ('i Index.t * 'a, 'bt) Base.Either.tAn indexed version of
match_.
val to_list : (Base.unit -> 'a -> _, Base.unit -> 'at -> _, [> many_getter ]) t -> 'at -> 'a Base.listExtract all the values targetted by an accessor in some composite data structure into a list.
val to_listi : ('i -> 'a -> _, Base.unit -> 'at -> _, [> many_getter ]) t -> 'at -> ('i Index.t * 'a) Base.listAn indexed version of
to_list.
val to_array : (Base.unit -> 'a -> _, Base.unit -> 'at -> _, [> many_getter ]) t -> 'at -> 'a Base.arrayExtract all the values targetted by an accessor in some composite data structure into an array.
val to_arrayi : ('i -> 'a -> _, Base.unit -> 'at -> _, [> many_getter ]) t -> 'at -> ('i Index.t * 'a) Base.arrayAn indexed version of
to_array.
val fold : (Base.unit -> 'a -> _, Base.unit -> 'at -> _, [> many_getter ]) t -> 'at -> init:'acc -> f:('acc -> 'a -> 'acc) -> 'accFold across all the values targetted by an accessor with an accumulator.
val foldi : ('i -> 'a -> _, Base.unit -> 'at -> _, [> many_getter ]) t -> 'at -> init:'acc -> f:('i Index.t -> 'acc -> 'a -> 'acc) -> 'accIndexed version of fold.
val iter : (Base.unit -> 'a -> _, Base.unit -> 'at -> _, [> many_getter ]) t -> 'at -> f:('a -> Base.unit) -> Base.unitIterate over all the values targetted by an accessor, applying the function argument to each one.
val iteri : ('i -> 'a -> _, Base.unit -> 'at -> _, [> many_getter ]) t -> 'at -> f:('i Index.t -> 'a -> Base.unit) -> Base.unitAn indexed version of
iter.
val length : (Base.unit -> _ -> _, Base.unit -> 'at -> _, [> many_getter ]) t -> 'at -> Base.intlength t atreturns the number of targets inat.
val is_empty : (Base.unit -> _ -> _, Base.unit -> 'at -> _, [> many_getter ]) t -> 'at -> Base.boolis_empty t atistrueiff there are no targets inat.
val sum : (module Base.Container.Summable with type t = 'sum) -> (Base.unit -> 'a -> _, Base.unit -> 'at -> _, [> many_getter ]) t -> 'at -> f:('a -> 'sum) -> 'sumsum (module Summable) t at ~freturns the sum off afor all targetsainat.
val sumi : (module Base.Container.Summable with type t = 'sum) -> ('i -> 'a -> _, Base.unit -> 'at -> _, [> many_getter ]) t -> 'at -> f:('i Index.t -> 'a -> 'sum) -> 'sumsumiis the indexed version ofsum.
val count : (Base.unit -> 'a -> _, Base.unit -> 'at -> _, [> many_getter ]) t -> 'at -> f:('a -> Base.bool) -> Base.intcount t at ~freturns the number of targets inatfor whichfevaluates to true.
val counti : ('i -> 'a -> _, Base.unit -> 'at -> _, [> many_getter ]) t -> 'at -> f:('i Index.t -> 'a -> Base.bool) -> Base.intcountiis the indexed version ofcount.
val exists : (Base.unit -> 'a -> _, Base.unit -> 'at -> _, [> many_getter ]) t -> 'at -> f:('a -> Base.bool) -> Base.boolexists t at ~freturnstrueiff there is a target inatfor whichfreturnstrue. This is a short-circuiting operation.
val existsi : ('i -> 'a -> _, Base.unit -> 'at -> _, [> many_getter ]) t -> 'at -> f:('i Index.t -> 'a -> Base.bool) -> Base.boolexistsiis the indexed version ofexists.
val for_all : (Base.unit -> 'a -> _, Base.unit -> 'at -> _, [> many_getter ]) t -> 'at -> f:('a -> Base.bool) -> Base.boolfor_all t at ~freturnstrueifffreturnstruefor all targets inat. This is a short-circuiting operation.
val for_alli : ('i -> 'a -> _, Base.unit -> 'at -> _, [> many_getter ]) t -> 'at -> f:('i Index.t -> 'a -> Base.bool) -> Base.boolfor_alliis the indexed version offor_all.
val find_map : (Base.unit -> 'a -> _, Base.unit -> 'at -> _, [> many_getter ]) t -> 'at -> f:('a -> 'b Base.option) -> 'b Base.optionfind_mapreturns the first evaluation offthat returnsSome.
val find_mapi : ('i -> 'a -> _, Base.unit -> 'at -> _, [> many_getter ]) t -> 'at -> f:('i Index.t -> 'a -> 'b Base.option) -> 'b Base.optionfind_mapiis the indexed version offind_map.
val find : (Base.unit -> 'a -> _, Base.unit -> 'at -> _, [> many_getter ]) t -> 'at -> f:('a -> Base.bool) -> 'a Base.optionfind t at ~freturns the first target inatfor which the evaluation offreturnstrue.
val findi : ('i -> 'a -> _, Base.unit -> 'at -> _, [> many_getter ]) t -> 'at -> f:('i Index.t -> 'a -> Base.bool) -> ('i Index.t * 'a) Base.optionfindiis the indexed version offind.
val min_elt : (Base.unit -> 'a -> _, Base.unit -> 'at -> _, [> nonempty_getter ]) t -> 'at -> compare:('a -> 'a -> Base.int) -> 'amin_elt t at ~compareusescompareto compare each target inatand returns the first target with the smallest value.
val min_elt_option : (Base.unit -> 'a -> _, Base.unit -> 'at -> _, [> many_getter ]) t -> 'at -> compare:('a -> 'a -> Base.int) -> 'a Base.optionmin_elt_option t at ~compareusescompareto compare each target inatand returns the first target with the smallest value, if any.
val max_elt : (Base.unit -> 'a -> _, Base.unit -> 'at -> _, [> nonempty_getter ]) t -> 'at -> compare:('a -> 'a -> Base.int) -> 'amax_elt t at ~compareusescompareto compare each target inatand returns the first target with the largest value.
val max_elt_option : (Base.unit -> 'a -> _, Base.unit -> 'at -> _, [> many_getter ]) t -> 'at -> compare:('a -> 'a -> Base.int) -> 'a Base.optionmax_elt_option t at ~compareusescompareto compare each target inatand returns the first target with the largest value, if any.
val hd : (Base.unit -> 'a -> _, Base.unit -> 'at -> _, [> nonempty_getter ]) t -> 'at -> 'ahd t atreturns the first targetted element ofat.
val hdi : ('i -> 'a -> _, Base.unit -> 'at -> _, [> nonempty_getter ]) t -> 'at -> 'i Index.t * 'aAn indexed version of
hd.
val hd_option : (Base.unit -> 'a -> _, Base.unit -> 'at -> _, [> many_getter ]) t -> 'at -> 'a Base.optionhd_option t atreturns the first targetted element ofat, if any.
val hd_optioni : ('i -> 'a -> _, Base.unit -> 'at -> _, [> many_getter ]) t -> 'at -> ('i Index.t * 'a) Base.optionAn indexed version of
hd_option.
val map_reduce : (Base.unit -> 'a -> _, Base.unit -> 'at -> _, [> many_getter ]) t -> 'at -> empty:'r -> combine:('r -> 'r -> 'r) -> f:('a -> 'r) -> 'rmap_reduce t at ~empty ~combine ~fappliesfto each targetted value inatand combines the results usingcombine. The result isemptyif there were no values.emptyandcombineare expected to satisfy the following properties:combine empty a = acombine a empty = acombine (combine a b) c = combine a (combine b c)
val map_reducei : ('i -> 'a -> _, Base.unit -> 'at -> _, [> many_getter ]) t -> 'at -> empty:'r -> combine:('r -> 'r -> 'r) -> f:('i Index.t -> 'a -> 'r) -> 'rAn indexed version of
map_reduce.
val map_reduce_nonempty : (Base.unit -> 'a -> _, Base.unit -> 'at -> _, [> nonempty_getter ]) t -> 'at -> combine:('r -> 'r -> 'r) -> f:('a -> 'r) -> 'rmap_reduce_nonempty t at ~combine ~fappliesfto each targetted value inatand combines the results usingcombine.combineis expected to satisfy the property:combine (combine a b) c = combine a (combine b c).
val map_reduce_nonemptyi : ('i -> 'a -> _, Base.unit -> 'at -> _, [> nonempty_getter ]) t -> 'at -> combine:('r -> 'r -> 'r) -> f:('i Index.t -> 'a -> 'r) -> 'rAn indexed version of
map_reduce_nonempty.
Modifying
val map : (Base.unit -> 'a -> 'b, Base.unit -> 'at -> 'bt, [> mapper ]) t -> 'at -> f:('a -> 'b) -> 'btmap t at ~fappliesfto each targetted value insideat, replacing it with the result.
val mapi : ('i -> 'a -> 'b, Base.unit -> 'at -> 'bt, [> mapper ]) t -> 'at -> f:('i Index.t -> 'a -> 'b) -> 'btmapiis the indexed version ofmap.
val folding_map : (Base.unit -> 'a -> 'b, Base.unit -> 'at -> 'bt, [> many ]) t -> 'at -> init:'acc -> f:('acc -> 'a -> 'acc * 'b) -> 'btfolding_mapis a version ofmapthat threads an accumulator through calls tof.
val folding_mapi : ('i -> 'a -> 'b, Base.unit -> 'at -> 'bt, [> many ]) t -> 'at -> init:'acc -> f:('i Index.t -> 'acc -> 'a -> 'acc * 'b) -> 'btfolding_mapiis the indexed version offolding_map.
val fold_map : (Base.unit -> 'a -> 'b, Base.unit -> 'at -> 'bt, [> many ]) t -> 'at -> init:'acc -> f:('acc -> 'a -> 'acc * 'b) -> 'acc * 'btfold_mapis a combination offoldandmapthat threads an accumulator through calls tof.
Monadic and Applicative functions
Signatures
module Functor = Accessor.Functormodule Applicative = Accessor.Applicativemodule Applicative_without_return = Accessor.Applicative_without_returnmodule Monad = Accessor.MonadThe monad signatures differ from the applicative ones in that some of the functions have an optional
howargument. They always default to`Sequential, which is the behavior that interleaves side effects with monadic effects. If you override this argument to`Parallelthen all the side effects are performed up front, and then the results are combined.
module Monad_without_return = Accessor.Monad_without_returnFunctors
module Of_functor = Accessor.Of_functorOf_functor,Of_functor2, andOf_functor3generate map-like functions that work under some "functor", which is like a monad or applicative, except that it only supportsmap.
module Of_functor2 = Accessor.Of_functor2module Of_functor3 = Accessor.Of_functor3module Of_applicative = Accessor.Of_applicativeOf_applicativeandOf_applicative2can be used to generate map-like functions that can use applicative effects. See alsoOf_monad, which gives more control over the relationship between side effects and monadic effects.
module Of_applicative2 = Accessor.Of_applicative2See
Of_applicative.
module Of_monad = Accessor.Of_monadOf_monadis similar toOf_applicative. There are two differences.
module Of_monad2 = Accessor.Of_monad2See
Of_monad.
module Of_applicative_without_return = Accessor.Of_applicative_without_returnLike
Of_applicative, but withoutreturn.
module Of_applicative_without_return2 = Accessor.Of_applicative_without_return2Like
Of_applicative2, but withoutreturn.
module Of_applicative_without_return3 = Accessor.Of_applicative_without_return3module Of_monad_without_return = Accessor.Of_monad_without_returnLike
Of_monad, but withoutreturn.
module Of_monad_without_return2 = Accessor.Of_monad_without_return2Like
Of_monad2, but withoutreturn.
module Of_monad_without_return3 = Accessor.Of_monad_without_return3Recursive update
val transform : (Base.unit -> 'a -> 'b, Base.unit -> 'a -> 'b, [> mapper ]) t -> 'a -> f:('b -> 'b) -> 'btransform t a ~fappliesfeverywhere it can inside ofaonce. It operates from the bottom up in one pass.tis used to find the children at each level, where the children are expected to have the same type as their parent.
val rewrite : (Base.unit -> 'a -> 'b, Base.unit -> 'a -> 'b, [> mapper ]) t -> 'a -> f:('b -> 'a Base.option) -> 'brewrite t a ~fapplies the rewrite rulefeverywhere it can inside ofauntil it cannot be applied anywhere else. It operates from the bottom up, retrying subtrees each time a rule is applied successfully.tis used to find the children at each level, where the children are expected to have the same type as their parent.
Type equality
module Identical = Accessor.IdenticalAn
Identical.tis similar to aType_equal.t, but it relates two pairs of types with each other instead of merely two types. It is a more natural way of using an equality accessor thanType_equal.twould be, since you only need to match on one constructor.
val identical : (Base.unit -> 'a -> 'b, Base.unit -> 'at -> 'bt, [> equality ]) t -> ('a, 'b, 'at, 'bt) Identical.tAn equality is more powerful even than an isomorphism. It can be used to prove that the types are equal using the
identicalfunction.
Construction
val construct : (_ -> _ -> 'b, _ -> _ -> 'bt, [> constructor ]) t -> 'b -> 'btconstructgoes the opposite way to most access patterns. It allows you to construct a composite data structure without reading from one.
Custom mappings
module Equality : sig ... endAn
equalitycan transform any mapping. There is no need for you to provide any functionality of your own.
module Isomorphism : sig ... endmodule Field : sig ... endmodule Variant : sig ... endmodule Constructor : sig ... endmodule Getter : sig ... endmodule Optional : sig ... endmodule Optional_getter : sig ... endmodule Nonempty : sig ... endmodule Nonempty_getter : sig ... endmodule Many : sig ... endmodule Many_getter : sig ... endmodule Mapper : sig ... endCreating accessors
Avoiding the value restriction
Deriving accessors
"Well behaved" accessors
Creation functions
Field accessors
val field : get:('at -> 'a) -> set:('at -> 'b -> 'bt) -> ('i -> 'a -> 'b, 'i -> 'at -> 'bt, [< field ]) tfield ~get ~setcreates a field accessor. A field accesses exactly one value within a composite data structure. For the field to be well behaved,getandsetshould satisfy the following properties:get (set at a) = aset at (get at) = atset (set at a) b = set at b
val field' : ('at -> 'a * ('b -> 'bt)) -> ('i -> 'a -> 'b, 'i -> 'at -> 'bt, [< field ]) tfield'is the same asfield, just with a slightly different interface.fieldis usually more convenient to use, butfield'can be useful to allowgetandsetto share the computation of finding the location to modify.
val of_field : ([> `Set_and_create ], 'r, 'a) Base.Field.t_with_perm -> ('i -> 'a -> 'a, 'i -> 'r -> 'r, [< field ]) tA
Field.tis sufficient to define a field accessor, but the resulting accessor might not be as polymorphic as it could have been if defined by hand or using@@deriving accessor.
val fieldi : get:('at -> 'i * 'a) -> set:('at -> 'b -> 'bt) -> (('i * 'it) -> 'a -> 'b, 'it -> 'at -> 'bt, [< field ]) tfieldiis the indexed version offield.
val fieldi' : ('at -> 'i * 'a * ('b -> 'bt)) -> (('i * 'it) -> 'a -> 'b, 'it -> 'at -> 'bt, [< field ]) tfieldi'is the indexed version offield'.
val of_fieldi : ([> `Set_and_create ], 'r, 'a) Base.Field.t_with_perm -> ((Base.string * 'it) -> 'a -> 'a, 'it -> 'r -> 'r, [< field ]) tA
Field.tis sufficient to define an indexed field accessor, where the index is the name of the field as a string. The resulting accessor might not be as polymorphic as it could have been if defined by hand or using@@deriving accessor.
Variant accessors
val variant : match_:('at -> ('a, 'bt) Base.Either.t) -> construct:('b -> 'bt) -> ('i -> 'a -> 'b, 'i -> 'at -> 'bt, [< variant ]) tvariant ~match_ ~constructcreates a variant accessor. A variant accesses at most one value within a composite data structure, and if it does access a value then that value is representative of the entire data structure. A well behaved variant should satisfy the following properties:match_ (construct a) = First a- if
match_ at = First athenconstruct a = at - if
match_ at = Second btthenat = bt
val varianti : match_:('at -> ('i * 'a, 'bt) Base.Either.t) -> construct:('b -> 'bt) -> (('i * 'it) -> 'a -> 'b, 'it -> 'at -> 'bt, [< variant ]) tvariantiis the indexed version ofvariant.
Optional accessors
val optional : match_:('at -> ('a, 'bt) Base.Either.t) -> set:('at -> 'b -> 'bt) -> ('i -> 'a -> 'b, 'i -> 'at -> 'bt, [< optional ]) toptional ~match_ ~setcreates an optional accessor. An optional accesses at most one value within a composite data structure. A well behaved optional should satisfy the following properties:match_ (set at a) = Either.First.map (match_ at) ~f:(const a)- if
match_ at = First athenset at a = at - if
match_ at = Second btthenat = btandset at b = at set (set at a) b = set at b
val optional' : ('at -> ('a * ('b -> 'bt), 'bt) Base.Either.t) -> ('i -> 'a -> 'b, 'i -> 'at -> 'bt, [< optional ]) toptional'is the same asoptional, just with a slightly different interface.optionalis usually more convenient to use, butoptional'can be useful to allowmatch_andsetto share the computation of finding the location to modify.
val optionali : match_:('at -> ('i * 'a, 'bt) Base.Either.t) -> set:('at -> 'b -> 'bt) -> (('i * 'it) -> 'a -> 'b, 'it -> 'at -> 'bt, [< optional ]) toptionaliis the indexed version ofoptional.
val optionali' : ('at -> ('i * 'a * ('b -> 'bt), 'bt) Base.Either.t) -> (('i * 'it) -> 'a -> 'b, 'it -> 'at -> 'bt, [< optional ]) toptionali'is the indexed version ofoptional'.
val filter_index : ('i Index.t -> Base.bool) -> ('i -> 'a -> 'a, 'i -> 'a -> 'a, [< optional ]) tfilter_index predicateaccesses the entire value if its index satisfiespredicate, otherwise it accesses nothing. Compose it with a many accessor to access a subset of values.
val filter_map_index : ('i Index.t -> 'j Index.t Base.option) -> ('j -> 'a -> 'a, 'i -> 'a -> 'a, [< optional ]) tfilter_map_index fis likefilter_index, but it can also modify the indices.
Isomorphism accessors
val isomorphism : get:('at -> 'a) -> construct:('b -> 'bt) -> ('i -> 'a -> 'b, 'i -> 'at -> 'bt, [< isomorphism ]) tisomorphism ~get ~constructcreates an isomorphism accessor. An isomorphism accesses exactly one value which exactly represents the entire data structure. A well behaved isomorphism should satisfy the following properties:get (construct b) = bconstruct (get at) = at
val isomorphismi : get:('at -> 'i * 'a) -> construct:('b -> 'bt) -> (('i * 'it) -> 'a -> 'b, 'it -> 'at -> 'bt, [< isomorphism ]) tisomorphismiis the indexed version ofisomorphism.
val map_index : ('i Index.t -> 'j Index.t) -> ('j -> 'a -> 'b, 'i -> 'a -> 'b, [< isomorphism ]) tmap_index fappliesfto the the indices that pass through it in a chain of composed accessors.
Mapper accessors
val mapper : ('at -> f:('a -> 'b) -> 'bt) -> ('i -> 'a -> 'b, 'i -> 'at -> 'bt, [< mapper ]) tmapper mapcreates a mapper accessor. A mapper can modify values inside a composite data structure, but cannot read anything out. A well behaved mapper should satisfy the following properties:map at ~f:Fn.id = atmap at ~f:(Fn.compose f g) = map (map at ~f:g) ~f
Many accessors
val many : ('at -> ('bt, 'a, 'b) Many.t) -> ('i -> 'a -> 'b, 'i -> 'at -> 'bt, [< many ]) tmany traversecreates amanyaccessor. Amanyaccesses any number of values within a composite data structure.To define a
manyaccessor, you must useAccessor.Many.t, which is an applicative. You should traverse the data structure as necessary, and each time you reach a value that should be accessed, applyAccessor.Many.accessto it.Here is an example of using
manyto define an accessor that reaches all the elements of a list:Accessor.many (fun at -> Accessor.Many.all (List.map at ~f:Accessor.Many.access))A well behaved many should satisfy the same properties as a well behaved mapper, but generalized for an applicative setting. The properties themselves are uselessly complicated when written out, but here they are anyway.
AandBare assumed to have theof_manyfunction generated byMany.Of_applicative, andComposeis assumed to be some functor behaving likeApplicative.Composethat also usesMany.Of_applicativeto generate anof_manyfunction.A.of_many (traverse at) ~access:A.return = A.return atCompose(A)(B).of_many (traverse at) ~access:(fun a -> A.map (g a) ~f) = A.map (A.of_many (traverse at) ~access:g) ~f:(fun at -> B.of_many (traverse at) ~access:f)
Nonempty accessors
val nonempty : ('at -> ('bt, 'a, 'b) Nonempty.t) -> ('i -> 'a -> 'b, 'i -> 'at -> 'bt, [< nonempty ]) tnonempty traversecreates a nonempty accessor. A nonempty accesses a nonzero number of values within a composite data structure.To define a
nonemptyaccessor, you must useAccessor.Nonempty.t, which is an applicative lackingreturn. You should traverse the data structure as necessary, and each time you reach a value that should be accessed, applyAccessor.Nonempty.accessto it.Here is an example of using
nonemptyto define an accessor that reaches both components of a tuple:Accessor.nonempty (fun (a, b) -> let open Accessor.Nonempty.Let_syntax in let%map_open a = access a and b = access b in a, b)A well behaved nonempty should satisfy the second property of a well behaved mapper, but generalized for an applicative setting. The property itself is uselessly complicated when written out, but here it is anyway.
AandBare assumed to have theof_nonemptyfunction generated byNonempty.Of_applicative_without_return, andComposeis assumed to be some functor behaving likeApplicative_without_return.Composethat also usesNonempty.Of_applicative_without_returnto generate anof_nonemptyfunction.Compose(A)(B).of_nonempty (traverse at) ~access:(fun a -> A.map (g a) ~f) = A.map (A.of_nonempty (traverse at) ~access:g) ~f:(fun at -> B.of_nonempty (traverse at) ~access:f)
val nonemptyi : ('at -> ('bt, 'i * 'a, 'b) Nonempty.t) -> (('i * 'it) -> 'a -> 'b, 'it -> 'at -> 'bt, [< nonempty ]) tnonemptyiis the indexed version ofnonempty.
Getter accessors
Optional getter accessors
val optional_getter : ('at -> 'a Base.option) -> ('i -> 'a -> _, 'i -> 'at -> _, [< optional_getter ]) toptional_getter getcreates an optional getter accessor. An optional getter reads at most one value from a composite data structure. There are no properties necessary for an optional getter to be well behaved.
val optional_getteri : ('at -> ('i * 'a) Base.option) -> (('i * 'it) -> 'a -> _, 'it -> 'at -> _, [< optional_getter ]) toptional_getteriis the indexed version ofoptional_getter.
Many getter accessors
val many_getter : ('at -> 'a Many_getter.t) -> ('i -> 'a -> 'b, 'i -> 'at -> 'bt, [< many_getter ]) tmany_getter map_reducecreates a many_getter accessor. A many getter reads any number of values from a composite data structure. There are no properties necessary for a many getter to be well behaved.To define a many_getter, you must use the
Many_getterinterface. LikeMany, it has anaccessfunction to designate which values to access. UnlikeMany, instead of an applicative interface, it hasemptyandappend(or( @ )) functions.Here is an example of defining a getter that reads all the elements of a list:
Accessor.many_getter (fun at -> Accessor.Many_getter.of_list (List.map at ~f:Accessor.Many_getter.access))
val many_getteri : ('at -> ('i * 'a) Many_getter.t) -> (('i * 'it) -> 'a -> 'b, 'it -> 'at -> 'bt, [< many_getter ]) tmany_getteriis the indexed version ofmany_getter.
Nonempty getter accessors
val nonempty_getter : ('at -> 'a Nonempty_getter.t) -> ('i -> 'a -> 'b, 'i -> 'at -> 'bt, [< nonempty_getter ]) tnonempty_getter map_reducecreates a nonempty getter accessor. A nonempty getter reads at least one value from a composite data structure. There are no properties necessary for a nonempty getter to be well behaved.To define a nonempty_getter, you must use the
Nonempty_getterinterface. LikeNonempty, it has anaccessfunction to designate which values to access. UnlikeNonempty, instead of an applicative style interface, it has anappend(or( @ )) function.Here is an example of defining a getter that reads both of the components of a tuple:
Accessor.nonempty_getter (fun (a, b) -> Accessor.Nonempty_getter.(access a @ access b))
val nonempty_getteri : ('at -> ('i * 'a) Nonempty_getter.t) -> (('i * 'it) -> 'a -> 'b, 'it -> 'at -> 'bt, [< nonempty_getter ]) tnonempty_getteriis the indexed version ofnonempty_getter.
Constructor accessors
val constructor : ('b -> 'bt) -> (_ -> _ -> 'b, _ -> _ -> 'bt, [< constructor ]) tconstructor constructcreates a constructor accessor. A constructor creates a composite data structure from an argument. There are no properties necessary for a constructor to be well behaved.
val of_variant : ('b -> 'bt) Base.Variant.t -> (_ -> _ -> 'b, _ -> _ -> 'bt, [< constructor ]) tA
Variant.tis not sufficient to define a variant accessor, but is at least sufficient to define a constructor accessor.
Transforming accessors
val invert : (Base.unit -> 'a -> 'b, Base.unit -> 'at -> 'bt, [> isomorphism ]) t -> ('i -> 'bt -> 'at, 'i -> 'b -> 'a, [< isomorphism ]) tTurn an isomorphism around.
invert (isomorphism ~get:f ~construct:g)isisomorphism ~get:g ~construct:f.
val getter_to_constructor : (Base.unit -> 'a -> _, Base.unit -> 'at -> _, [> getter ]) t -> (_ -> _ -> 'at, _ -> _ -> 'a, [< constructor ]) tTurn a getter into a constructor.
getter_to_constructor (getter f)isconstructor f.
val constructor_to_getter : (_ -> _ -> 'b, _ -> _ -> 'bt, [> constructor ]) t -> ('i -> 'bt -> _, 'i -> 'b -> _, [< getter ]) tTurn a constructor into a getter.
constructor_to_getter (constructor f)isgetter f.
val many_to_list_field : (Base.unit, 'a, 'at, [> many ]) Simple.t -> (_, 'a Base.list, 'at, [< field ]) Simple.tGiven a
manyaccessor, generate afieldaccessor that accesses all the elements that would be accessed by themanyaccessor in the form of a list. When replacing, if the list is too short then later elements in the data structure are left alone, and if the list is too long then extraneous elements are not used.The resulting accessor is only well-behaved if you preserve the length of the list across getting and setting.
module Bool = Accessor_base__.Accessor_boolmodule Either = Accessor_base__.Accessor_eithermodule Error = Accessor_base__.Accessor_errormodule Float = Accessor_base__.Accessor_floatmodule Fn = Accessor_base__.Accessor_fnmodule Info = Accessor_base__.Accessor_infomodule Int = Accessor_base__.Accessor_intmodule List = Accessor_base__.Accessor_listmodule Map = Accessor_base__.Accessor_mapmodule Maybe_bound = Accessor_base__.Accessor_maybe_boundmodule Option = Accessor_base__.Accessor_optionmodule Or_error = Accessor_base__.Accessor_or_errormodule Ordering = Accessor_base__.Accessor_orderingmodule Result = Accessor_base__.Accessor_resultmodule Sequence = Accessor_base__.Accessor_sequencemodule Set = Accessor_base__.Accessor_setmodule Sexp = Accessor_base__.Accessor_sexpmodule Sign = Accessor_base__.Accessor_signmodule Sign_or_nan = Accessor_base__.Accessor_sign_or_nanmodule Source_code_position = Accessor_base__.Accessor_source_code_positionmodule Staged = Accessor_base__.Accessor_stagedmodule String = Accessor_base__.Accessor_stringmodule Tuple2 = Accessor_base__.Accessor_tuple2