-
travesty
-
-
travesty.containers
-
-
travesty.core_kernel_exts
Library
Module
Module type
Parameter
Class
Class type
Utility functions for building traversals.
Parameters
module M : Base.Monad.S
Signature
type 'a traversal = 'a -> 'a M.t
traversal
is shorthand for a traversal function over M
.
Variants
Functions beginning proc_variant
are useful for building traversable containers on top of Variantslib's map
function.
Here's an example where we define a generic traversal function over a variant type using proc_variant1 and proc_variant3, then use it to build a traversable container instance for inspecting and modifying a specific type of data regardless of variant.
(* This type describes x86 operands: *)
type t =
| Location of Location.t
| Immediate of Disp.t
| String of string
| Typ of string
| Bop of t * operator * t [@@deriving variants]
(* We use the helpers to build an intermediate mapper... *)
module Base_map (M : Monad.S) = struct
module F = Travesty.Traversable.Helpers (M)
let rec map_m (x : t) ~location ~immediate ~string ~typ ~bop
: t M.t =
Variants.map x
~location:(F.proc_variant1 location)
~immediate:(F.proc_variant1 immediate)
~string:(F.proc_variant1 string)
~typ:(F.proc_variant1 typ)
(* Note that this recursively folds down the operands,
and that the [bop] function only receives the operator. *)
~bop:(F.proc_variant3 (fun (l, b, r) ->
let open M.Let_syntax in
let%bind l' = map_m ~location ~immediate ~string ~typ ~bop l in
let%bind b' = bop b in
let%map r' = map_m ~location ~immediate ~string ~typ ~bop r in
(l', b', r')))
;;
end
(* ...then use it to build a traversable container over all of
the symbols in an operand. *)
module On_symbols
: Travesty.Traversable.S0_container with type t := t
and type elt := string =
Travesty.Traversable.Make_container0 (struct
type nonrec t = t
module Elt = String
module On_monad (M : Monad.S) = struct
module B = Base_map (M)
(* Recursively using other traversables: *)
module L = Location.On_symbols.On_monad (M)
module D = Disp.On_symbols.On_monad (M)
let map_m t ~f =
B.map_m t
~location:(L.map_m ~f)
~immediate:(D.map_m ~f)
(* These don't contain symbols: *)
~string:M.return
~typ:M.return
~bop:M.return
end
end)
val proc_variant0 : Base.unit traversal -> 'cont Base.Variant.t -> 'cont M.t
proc_variant0 f variant
lifts a traversal f
over a Variantslib nullary variant constructor variant
.
val proc_variant1 :
'a traversal ->
('a -> 'cont) Base.Variant.t ->
'a ->
'cont M.t
proc_variant1 f variant a
lifts a traversal f
over a Variantslib unary variant constructor variant
with argument a
.
val proc_variant2 :
('a * 'b) traversal ->
('a -> 'b -> 'cont) Base.Variant.t ->
'a ->
'b ->
'cont M.t
proc_variant2 f variant a b
lifts a traversal f
over a Variantslib binary variant constructor variant
with arguments a
and b
.
val proc_variant3 :
('a * 'b * 'c) traversal ->
('a -> 'b -> 'c -> 'cont) Base.Variant.t ->
'a ->
'b ->
'c ->
'cont M.t
proc_variant3 f variant a b c
lifts a traversal f
over a Variantslib ternary variant constructor variant
with arguments a
, b
, and c
.
Fields
The function proc_field
is useful for building traversable containers on top of Fieldslib's fold
function.
Here's an example where we define a generic traversal function over a record type using proc_field, then use it to build a traversable container instance for inspecting and modifying a specific type of data inside the record.
(* Type for holding x86 memory references. *)
type t =
{ seg : Reg.t option (* segment register *)
; disp : Disp.t option (* displacement *)
; base : Reg.t option (* base register *)
; index : Index.t option (* index *)
} [@@deriving fields]
(* First, build a generic traversal function (this isn't,
itself, a Traversable)... *)
module Base_map (M : Monad.S) = struct
module F = Travesty.Traversable.Helpers (M)
let map_m indirect ~seg ~disp ~base ~index =
Fields.fold
~init:(M.return indirect)
~seg:(F.proc_field seg)
~disp:(F.proc_field disp)
~base:(F.proc_field base)
~index:(F.proc_field index)
end
(* Now, we can build a traversable container instance.
This one extracts symbols from memory references. *)
module On_symbols
: Travesty.Traversable.S0_container with type t := t
and type elt := string =
Travesty.Traversable.Make_container0 (struct
type nonrec t = t
module Elt = String
module Set = String.Set
module On_monad (M : Monad.S) = struct
module B = Base_map (M)
module D = Disp.On_symbols.On_monad (M)
module O = My_option.On_monad (M)
let map_m t ~f =
B.map_m t
(* Chained monadic traversal. *)
~disp:(O.map_m ~f:(D.map_m ~f))
(* Segments, bases, and indices have no symbols. *)
~seg:M.return
~base:M.return
~index:M.return
end
end)
val proc_field :
'elt traversal ->
'cont M.t ->
([> `Set_and_create ], 'cont, 'elt) Base.Field.t_with_perm ->
'cont M.t
proc_field f state field container original
lifts a traversal f
to a form comparible with Fieldslib's fold
function.