package travesty

  1. Overview
  2. Docs
Legend:
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.