123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292(* This file is part of 'travesty'.
Copyright (c) 2018 by Matt Windsor
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. *)(** Signatures for monadic traversal. *)openBase(** {2:generic The generic signature}
As with {{!Mappable}Mappable}, we define the signature of
traversable structures in an arity-generic way, then specialise
it for arity-0 and arity-1 types.
*)(** [Generic] describes monadic traversal on either an arity-0 or
arity-1 type.
- For arity-0 types, use {{!S0}S0}: ['a t] becomes [t], and
['a elt] becomes [elt];
- For arity-1 types, use {{!S1}S1}: ['a t] becomes ['a t],
and ['a elt] becomes ['a].
*)moduletypeGeneric=sigincludeTypes_intf.Generic(** [Generic] refers to the container type as ['a t], and the element type
as ['a elt]; substitute [t]/[elt] (arity-0) or ['a t]/['a] (arity-1)
accordingly below. *)moduleM:Monad.S(** [M] is the monad over which we're fold-mapping. *)valmap_m:'at->f:('aelt->'beltM.t)->'btM.t(** [map_m c ~f] maps [f] over every [t] in [c], threading through
monadic state.
Example:
{[
(* T_list adds monadic traversals to a list;
With_errors (in S1_container) implements them on the On_error
monad. *)
let f x =
Or_error.(if 0 < x then error_string "negative!" else ok x)
in
T_list.With_errors.map_m integers ~f
]}
*)end(** {2:sigs Basic signatures} *)(** [S0] is the signature of a monadic traversal over arity-0
types. *)moduletypeS0=sigincludeTypes_intf.S0includeGenericwithtype'at:=tandtype'aelt:=eltend(** [S1] is the signature of a monadic traversal over arity-1
types. *)moduletypeS1=sigtype'at(** The type of the container to map over. *)(** [S1]s can traverse: when the container type is ['a t],
the element type is ['a]. *)includeGenericwithtype'at:='atandtype'aelt:='aend(** {2:build Building containers from traversable types}
Any traversable type can be turned into a Core container, using the monadic
fold to implement all container functionality. The unified signature of a
Core container with monadic traversals is {{!S0_container}S0_container}
(arity 0) or {{!S1_container}S1_container} (arity 1).
To satisfy these signatures for new types, implement {{!Basic0}Basic0} or
{{!Basic1}Basic1}, and use the corresponding [Make] functor in
{{!Traversable}Traversable}.
For types that are _already_ Core containers, or types where custom
implementation of the Core signature are desired, implement
{{!Basic_container0}Basic_container0} or
{{!Basic_container1}Basic_container1}, and use the [Extend] functors. *)(** {3 Input signatures} *)(** [Basic0] is the minimal signature that traversable containers of
arity 0 must implement to be extensible into
{{!S0_container}S0_container}. *)moduletypeBasic0=sigtypet(** The container type. *)moduleElt:Equal.S(** [Elt] contains the element type, which must have equality. *)moduleOn_monad(M:Monad.S):S0withtypet:=tandtypeelt:=Elt.tandmoduleM:=M(** [On_monad] implements monadic traversal for a given monad [M]. *)end(** [Basic_container0] combines {{!Basic0}Basic0} and the Core container
signature, and is used for extending existing containers into
{{!S0_container}S0_container}s. *)moduletypeBasic_container0=sigincludeBasic0includeContainer.S0withtypet:=tandtypeelt:=Elt.tend(** [Basic1] is the minimal signature that traversable containers of arity 1
must implement to be extensible into. *)moduletypeBasic1=sigtype'at(** The container type. *)moduleOn_monad(M:Monad.S):S1withtype'at:='atandmoduleM:=M(** [On_monad] implements monadic traversal for a given monad. *)end(** [Basic_container1] combines {{!Basic1}Basic1} and the Core container
signature, and is used for extending existing containers into
{{!S1_container}S1_container}s. *)moduletypeBasic_container1=sigincludeBasic1includeContainer.S1withtype'at:='atend(** {3 Helper signatures} *)(** [Generic_on_monad] extends [Generic] to contain various derived
operators; we use it to derive the signatures of the various
[On_monad] modules. *)moduletypeGeneric_on_monad=sigincludeGenericvalfold_map_m:'at->f:('acc->'aelt->('acc*'belt)M.t)->init:'acc->('acc*'bt)M.t(** [fold_map_m c ~f ~init] folds [f] monadically over every [t] in
[c], threading through an accumulator with initial value
[init]. *)valfold_m:'at->init:'acc->f:('acc->'aelt->'accM.t)->'accM.t(** [fold_m x ~init ~f] folds the monadic computation [f] over [x],
starting with initial value [init], and returning the final
value inside the monadic effect. *)valiter_m:'at->f:('aelt->unitM.t)->unitM.t(** [iter_m x ~f] iterates the monadic computation [f] over [x],
returning the final monadic effect. *)valmapi_m:f:(int->'aelt->'beltM.t)->'at->'btM.t(** [mapi_m ~f x] behaves as [mapM], but also supplies [f] with the
index of the element. This index should match the actual
position of the element in the container [x]. *)end(** [On_monad1] extends [Generic_on_monad] with functionality that
only works on arity-1 containers. *)moduletypeOn_monad1=sigtype'atincludeGeneric_on_monadwithtype'at:='atandtype'aelt:='avalsequence_m:'aM.tt->'atM.t(** [sequence_m x] lifts a container of monads [x] to a monad
containing a container, by sequencing the monadic effects from
left to right. *)end(** [Generic_container] is a generic interface for traversable
containers, used to build [Container0] (arity-0) and [Container1]
(arity-1). *)moduletypeGeneric_container=sigincludeTypes_intf.GenericmoduleOn_monad:functor(M:Monad.S)->Generic_on_monadwithtype'at:='atandtype'aelt:='aeltandmoduleM:=M(** [On_monad] implements monadic traversal operators for
a given monad [M]. *)includeContainer.Genericwithtype'at:='atandtype'aelt:='aelt(** We can do generic container operations. *)includeMappable.Genericwithtype'at:='atandtype'aelt:='aelt(** We can do non-monadic mapping operations. *)valfold_map:'at->f:('acc->'aelt->('acc*'belt))->init:'acc->('acc*'bt)(** [fold_map c ~f ~init] folds [f] over every [t] in [c], threading
through an accumulator with initial value [init]. *)valmapi:f:(int->'aelt->'belt)->'at->'bt(** [mapi ~f t] maps [f] across [t], passing in an increasing
position counter. *)moduleWith_errors:Generic_on_monadwithtype'at:='atandtype'aelt:='aeltandmoduleM:=Or_error(** [With_errors] specialises [On_monad] to the error monad. *)end(** {3 Signatures for traversable containers} *)(** [S0_container] is a generic interface for arity-0 traversable
containers. *)moduletypeS0_container=sigmoduleElt:Equal.S(** Elements must have equality. While this is an extra
restriction on top of the Core equivalent, it is required
by {{!Traversable.Make_container0}Make_container0}, and helps
us define chaining operations. *)includeTypes_intf.S0withtypeelt=Elt.t(** We export [Elt.t] as [elt] for compatibility with Core-style
containers. *)includeGeneric_containerwithtype'at:=tandtype'aelt:=Elt.tincludeMappable.S0_containerwithtypet:=tandtypeelt:=Elt.tend(** [S1_container] is a generic interface for arity-1 traversable
containers. It also includes the extensions from {{!Mappable}Mappable}. *)moduletypeS1_container=sig(** ['a t] is the type of the container, parametrised over the
element type ['a]. *)type'atmoduleOn_monad(M:Monad.S):On_monad1withtype'at:='atandmoduleM:=M(** [On_monad] implements monadic folding and mapping operators for
a given monad [M], including arity-1 specific operators. *)moduleWith_errors:On_monad1withtype'at:='atandmoduleM:=Or_error(** [With_errors] is shorthand for [On_monad (Or_error)]. *)includeGeneric_containerwithtype'at:='atandtype'aelt:='aandmoduleOn_monad:=On_monadandmoduleWith_errors:=With_errors;;includeMappable.S1_containerwithtype'at:='atincludeMappable.Extensions1withtype'at:='atmoduleWith_elt(Elt:Equal.S):S0_containerwithtypet:=Elt.ttandmoduleElt=Elt(** [With_elt (Elt)] demotes this [S1_container] to a
{{!S0_container}S0_container} by fixing the element type to that mentioned
in [Elt]. *)end