package ppx_typed_fields

  1. Overview
  2. Docs
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source

Source file the_map.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
open! Core
include The_map_intf

module Make_plain (Key : Typed_fields_lib.Common.S) (Data : Data) = struct
  module Key_mod = struct
    include Key

    let type_id = Type_ids.type_id
    let sexp_of_t _ t = Packed.sexp_of_t { f = T t }
  end

  include
    Univ_map.Make
      (Key_mod)
      (struct
        include Data

        let sexp_of_t _ = sexp_of_opaque
      end)

  module Key = Key_mod

  let find = find_exn
  let change = change_exn

  type creator = { f : 'a. 'a Key.t -> 'a Data.t }

  let create creator =
    List.fold Key.Packed.all ~init:empty ~f:(fun acc { f = Key.Packed.T t } ->
      add_exn acc ~key:t ~data:(creator.f t))
  ;;
end

module Make (Key : Typed_fields_lib.Common.S) (Data : Data) = struct
  module Key = Key
  module Data = Data
  module Base = Make_plain (Key) (Data)

  type creator = Base.creator = { f : 'a. 'a Key.t -> 'a Data.t }

  type sexper =
    { individual : 'a. 'a Key.t -> 'a -> Sexp.t
    ; container : 'a. ('a -> Sexp.t) -> 'a Data.t -> Sexp.t
    }

  type t =
    { base : Base.t
    ; sexper : sexper option
    }

  let create ?sexper creator = { base = Base.create creator; sexper }
  let set t ~key ~data = { t with base = Base.set t.base ~key ~data }
  let change t key ~f = { t with base = Base.change t.base key ~f }
  let find t key = Base.find t.base key

  module As_applicative = struct
    module type S = sig
      type 'a t = 'a Data.t

      val map : 'a t -> f:('a -> 'b) -> 'b t
      val all : 'a t list -> 'a list t
    end

    module type S_for_other_map = sig
      type 'a t

      val map : 'a t -> f:('a -> 'b) -> 'b t
      val all : 'a t list -> 'a list t

      type 'a s

      val translate : 'a Data.t -> 'a s t
    end

    module Id = struct
      type 'a t = 'a
    end

    module Id_map = Make_plain (Key) (Id)

    type creator = { f : 'a. 'a Key.t -> 'a }

    let transpose (module A : S) t ~create =
      t.base
      |> Base.to_alist
      |> List.map ~f:(function T (key, a) ->
        A.map a ~f:(fun a -> Id_map.Packed.T (key, a)))
      |> A.all
      |> A.map ~f:(fun all ->
        let map = Id_map.of_alist_exn all in
        create { f = (fun k -> Id_map.find map k) })
    ;;

    module To_other_map
        (A : S_for_other_map)
        (M : S_plain with type 'a Key.t = 'a Key.t and type 'a Data.t = 'a A.s) =
    struct
      module Inner =
        Make_plain
          (Key)
          (struct
            type 'a t = 'a A.s
          end)

      let run t =
        t.base
        |> Base.to_alist
        |> List.map ~f:(function T (key, a) ->
          A.map (A.translate a) ~f:(fun a -> Inner.Packed.T (key, a)))
        |> A.all
        |> A.map ~f:(fun alist ->
          let m = Inner.of_alist_exn alist in
          M.create { f = (fun k -> Inner.find m k) })
      ;;
    end
  end

  let sexp_of_t t =
    match t.sexper with
    | None -> Base.sexp_of_t t.base
    | Some sexpers ->
      t.base
      |> Base.to_alist
      |> List.map ~f:(function T (k, v) ->
        let sexp_of_a = sexpers.container (sexpers.individual k) v in
        Sexp.List [ Key.Packed.sexp_of_t { f = T k }; sexp_of_a ])
      |> Sexp.List
  ;;
end

module Make_for_records (Key : Typed_fields_lib.S) (Data : Data) = struct
  let create_derived_on = Key.create

  module Original_key = Key
  include Make (Key) (Data)

  let transpose_applicative { f } (module A : As_applicative.S) =
    let t = create { f } in
    As_applicative.transpose (module A) t ~create:(fun { f } -> create_derived_on { f })
  ;;

  (* Re-export Key as Typed_fields_lib.S *)
  module Key = Original_key
end