Legend:
Library
Module
Module type
Parameter
Class
Class type
Utility functions for building traversals.
Parameters
moduleM : Base.Monad.S
Signature
type'a traversal = 'a->'aM.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->'contBase.Variant.t->'contM.t
proc_variant0 f variant lifts a traversal f over a Variantslib nullary variant constructor variant.
val proc_variant1 :
'atraversal->('a->'cont)Base.Variant.t->'a->'contM.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->'contM.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->'contM.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 :
'elttraversal->'contM.t->([> `Set_and_create ], 'cont, 'elt)Base.Field.t_with_perm->'contM.t
proc_field f state field container original lifts a traversal f to a form comparible with Fieldslib's fold function.