Source file lwt_list.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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
(* This file is part of Lwt, released under the MIT license. See LICENSE.md for
   details, or visit https://github.com/ocsigen/lwt/blob/master/LICENSE.md. *)



(* A survey and measurements of more optimized implementations can be found at:

    https://jsthomas.github.io/map-comparison.html

   See discussion in https://github.com/ocsigen/lwt/pull/347. *)
let tail_recursive_map f l =
  List.rev (List.rev_map f l)

let tail_recursive_mapi_rev f l =
  let rec inner acc i = function
    | [] -> acc
    | hd::tl -> (inner [@ocaml.tailcall]) ((f i hd)::acc) (i + 1) tl
  in
  inner [] 0 l

open Lwt.Infix

let rec iter_s f l =
  match l with
  | [] ->
    Lwt.return_unit
  | x :: l ->
    Lwt.apply f x >>= fun () ->
    iter_s f l

let iter_p f l =
  let ts = List.rev_map (Lwt.apply f) l in
  Lwt.join ts

let rec iteri_s i f l =
  match l with
  | [] ->
    Lwt.return_unit
  | x :: l ->
    Lwt.apply (f i) x >>= fun () ->
    iteri_s (i + 1) f l

let iteri_s f l = iteri_s 0 f l

let iteri_p f l =
  let f' i = Lwt.apply (f i) in
  let ts = tail_recursive_mapi_rev f' l in
  Lwt.join ts

let map_s f l =
  let rec inner acc = function
    | [] -> List.rev acc |> Lwt.return
    | hd::tl ->
      Lwt.apply f hd >>= fun r ->
      (inner [@ocaml.tailcall]) (r::acc) tl
  in
  inner [] l

let rec _collect_rev acc = function
  | [] ->
    Lwt.return acc
  | t::ts ->
    t >>= fun i ->
    (_collect_rev [@ocaml.tailcall]) (i::acc) ts

let map_p f l =
  let ts = List.rev_map (Lwt.apply f) l in
  _collect_rev [] ts

let filter_map_s f l =
  let rec inner acc = function
    | []     -> List.rev acc |> Lwt.return
    | hd::tl ->
      Lwt.apply f hd >>= function
      | Some v -> (inner [@ocaml.tailcall]) (v::acc) tl
      | None -> (inner [@ocaml.tailcall]) acc tl
  in
  inner [] l

let filter_map_p f l =
  let rec _collect_optional_rev acc = function
  | []    -> Lwt.return acc
  | t::ts ->
    t >>= function
    | Some v -> (_collect_optional_rev [@ocaml.tailcall]) (v::acc) ts
    | None -> (_collect_optional_rev [@ocaml.tailcall]) acc ts
  in
  let ts = List.rev_map (Lwt.apply f) l in
  _collect_optional_rev [] ts

let mapi_s f l =
  let rec inner acc i = function
    | []     -> List.rev acc |> Lwt.return
    | hd::tl ->
      Lwt.apply (f i) hd >>= fun v ->
      (inner [@ocaml.tailcall]) (v::acc) (i+1) tl
  in
  inner [] 0 l

let mapi_p f l =
  let f' i = Lwt.apply (f i) in
  let ts = tail_recursive_mapi_rev f' l in
  _collect_rev [] ts

let rec rev_map_append_s acc f l =
  match l with
  | [] ->
    Lwt.return acc
  | x :: l ->
    Lwt.apply f x >>= fun x ->
    rev_map_append_s (x :: acc) f l

let rev_map_s f l =
  rev_map_append_s [] f l

let rec rev_map_append_p acc f l =
  match l with
  | [] ->
    acc
  | x :: l ->
    rev_map_append_p
      (Lwt.apply f x >>= fun x ->
       acc >|= fun l ->
       x :: l) f l

let rev_map_p f l =
  rev_map_append_p Lwt.return_nil f l

let rec fold_left_s f acc l =
  match l with
  | [] ->
    Lwt.return acc
  | x :: l ->
    Lwt.apply (f acc) x >>= fun acc ->
    (fold_left_s [@ocaml.tailcall]) f acc l

let fold_right_s f l acc =
  let rec inner f a = function
    | []     -> Lwt.return a
    | hd::tl -> (Lwt.apply (f hd) a) >>= fun a' ->
      (inner [@ocaml.tailcall]) f a' tl
  in
  inner f acc (List.rev l)

let rec for_all_s f l =
  match l with
  | [] ->
    Lwt.return_true
  | x :: l ->
    Lwt.apply f x >>= function
    | true ->
      (for_all_s [@ocaml.tailcall]) f l
    | false ->
      Lwt.return_false

let for_all_p f l =
  map_p f l >>= fun bl -> List.for_all (fun x -> x) bl |> Lwt.return

let rec exists_s f l =
  match l with
  | [] ->
    Lwt.return_false
  | x :: l ->
    Lwt.apply f x >>= function
    | true ->
      Lwt.return_true
    | false ->
      (exists_s [@ocaml.tailcall]) f l

let exists_p f l =
  map_p f l >>= fun bl -> List.exists (fun x -> x) bl |> Lwt.return

let rec find_s f l =
  match l with
  | [] ->
    Lwt.fail Not_found
  | x :: l ->
    Lwt.apply f x >>= function
    | true ->
      Lwt.return x
    | false ->
      (find_s [@ocaml.tailcall]) f l

let _optionalize f x =
  f x >>= fun b -> if b then Lwt.return (Some x) else Lwt.return_none

let filter_s f l =
  filter_map_s (_optionalize f) l

let filter_p f l =
   filter_map_p (_optionalize f) l

let partition_s f l =
  let rec inner acc1 acc2 = function
    | []     -> Lwt.return (List.rev acc1, List.rev acc2)
    | hd::tl -> Lwt.apply f hd >>= fun b ->
        if b then
          inner (hd::acc1) acc2 tl
        else
          inner acc1 (hd::acc2) tl
  in
  inner [] [] l

let partition_p f l =
  let g x = Lwt.apply f x >>= fun b -> Lwt.return (b, x) in
  map_p g l >>= fun tl ->
  let group1 = tail_recursive_map snd @@ List.filter fst tl in
  let group2 =
    tail_recursive_map snd @@ List.filter (fun x -> not @@ fst x) tl in
  Lwt.return (group1, group2)