-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathgeneric_util_list.ml
More file actions
170 lines (137 loc) · 4.75 KB
/
Copy pathgeneric_util_list.ml
File metadata and controls
170 lines (137 loc) · 4.75 KB
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
(** Useful functions on lists. *)
open Generic_util
open App.T
open Applicative.T
let (-<) = Fun.(-<)
(** [foldr c n l = List.fold_right c l n] *)
let foldr c n l = List.fold_right c l n
(** [cons] is useful when we want partial application of the list constructor. *)
let cons x xs = x :: xs
(** [from_to a b = [a; a+1; ... ; b]] *)
let rec from_to a b =
if a > b then []
else a :: from_to (a+1) b
(** [replicate n x = [x; x; ...; x]] with [x] repeated [n] times. *)
let rec replicate n x =
if n <= 0 then [] else x :: replicate (n-1) x
(** [with_indices [x0; x1; ...; xn] = [(0,x0); (1,x1); ... ; (n, xn)]] *)
let with_indices xs =
let rec go n = function
| [] -> []
| x :: xs -> (n,x) :: go (n+1) xs
in go 0 xs
(** [find_index p xs] is the index of the first element of [xs] for which the predicate [p] is true:
[p (List.nth xs (find_index p xs)) == true]
and [(n < find_index p xs ==> p (List.nth xs n) == false]
@raise Not_found if no element verifies the predicate
*)
let find_index p = (* find_index p = fst -< List.find (p -< snd) -< with_indices *)
let rec go n = function
| [] -> raise Not_found
| y :: ys -> if p y then n
else go (n+1) ys
in go 0
(** [index x xs] is the index of the first element of [xs] equal to [x].
[index x = find_index (fun y -> x = y)]
[List.nth xs (index x xs) = x]
Uses Pervasives.(=)
@raise Not_found if [x] is not an element of the list
*)
let index x = find_index (fun y -> x = y)
(** [findOpt p xs] returns [Some x] if [x] is the first
element of the list [xs] verifying the predicate [p]. or
[None] if no element verifies the predicate. This
function is total. *)
let find_opt p xs =
try Some (List.find p xs)
with Not_found -> None
(** [take_while p l] returns the longest prefix of [l] whose
elements make [p] true.*)
let rec take_while p = function
| [] -> []
| h :: t ->
if p h then h :: take_while p t else []
(** [drop_while p l] returns the suffix of [l] after removing
the longest prefix of [l] whose elements make [p] true.
{[
take_while p l @ drop_while p l = l
]}
*)
let rec drop_while p = function
| [] -> []
| h :: t as l ->
if p h then drop_while p t else l
(** [find_some f l] applies an option-valued function [f] to
the elements of a list [l] and returns the first element that is not [None]
or [None] if no such element exists.
*)
let find_some f xs =
let ys = drop_while (fun x -> f x = None) xs
in match ys with
| [] -> None
| x :: _ -> f x
(** [filter_some f l] applies [f] to every element [x] of the
list [l] yielding either [None] which is thrown away, or
[Some y] in which case [y] is kept.
{[
filter p = filter_some (fun x -> if p x then Some x else None)
]}
*)
let filter_some f xs =
let unopt = function
| None -> assert false
| Some x -> x
and some x = x <> None
in let open List in
map unopt (filter some (map f xs))
(** [set i x xs] computes a new list where the [i]-th element
of [xs] is [x], the rest of the list is unchanged. Counting
from [0].
If [i] is greater than the length of the list or if [i]
is negative, then the original list is returned.
*)
let set n x xs =
let rec go n = function
| [] -> []
| y :: ys ->
if n = 0
then x :: ys
else y :: go (n-1) ys
in
if n < 0 then xs else go n xs
(** {[concat_map f x = concat -< map f]}
[concat_map] is the flipped bind operator of the list monad
*)
let concat_map f xs = List.concat (List.map f xs)
let monoid = Monoid.list
let monad = Monad.list
(** Raised by {!sl_insert} when trying to insert an element that is already in the list. *)
exception Insert_duplicate
(** [sl_insert leq x xs] inserts the new element [x] in the sorted list [xs] using the pre-order [<=].
@raise Insert_duplicate when [x] is already in [xs].
*)
let rec sl_insert leq x = function
| [] -> [x]
| y :: ys as yys -> if leq x y then
if leq y x then raise Insert_duplicate
else x :: yys
else y :: sl_insert leq x ys
(** Raised by {!match_list}. *)
exception Match_list_failure
(** [match_list] tries to apply a function to the first
element of a list. If a [Match_failure] is caught, we
proceed with the rest of the list. If no more element is available (empty list),
the exception [Match_list_failure] is raised.
@raise Match_list_failure if the list is empty or if all the elements of the list
caused a [Match_failure].
*)
let match_list f =
let rec go = function
| [] -> raise Match_list_failure
| h :: t -> try f h
with Match_failure (_,_,_) -> go t
in go
let rec traverse a f = let open App.T in function
| [] -> a.pure []
| h :: t -> Applicative.liftA2 a cons (f h) (traverse a f t)
let sequence a = traverse a (fun x -> x)