summaryrefslogtreecommitdiff
path: root/lib/zipper.mli
diff options
context:
space:
mode:
Diffstat (limited to 'lib/zipper.mli')
-rw-r--r--lib/zipper.mli258
1 files changed, 258 insertions, 0 deletions
diff --git a/lib/zipper.mli b/lib/zipper.mli
new file mode 100644
index 0000000..c3c79a6
--- /dev/null
+++ b/lib/zipper.mli
@@ -0,0 +1,258 @@
1open Base
2
3(** Linear zippers.
4
5 A zipper represents {b a paused traversal} of a certain data
6 structure. A linear zipper of type ['a zipper] represents a zipper
7 over a sequence of ['a] elements.
8
9 One can access the {b focused element} of the zipper with [focus].
10 The focus of a zipper is also known as the the {b cursor} of the
11 zipper, and can be moved back and forth with [left] and [right].
12
13 Elements can be added or removed at the cursor's position with
14 [push] and [pop] operations. Variants are available, e.g., to act
15 before the cursor, with suffix [_before], or after the cursor, with
16 suffix [_after]. *)
17
18type !+'a zipper
19(** A zipper is represented as a {b pair} of sequences of type ['a]. The
20 focus of the zipper is the element at the head of the second
21 sequence, if any.
22
23 Note that the first sequence is reversed. Given a sequence
24 [[1; 2; 3; 4; {5}; 6; 7]], where we represent the cursor using
25 curly braces [{_}], its representation as a zipper is
26 [([4; 3; 2; 1], [5; 6; 7])]. *)
27
28type !+'a t = 'a zipper
29(** An alias for the ['a zipper] type. *)
30
31val empty : 'a zipper
32(** Return an empty zipper *)
33
34val before : 'a zipper -> 'a Sequence.t
35(** Return the sequence before the cursor *)
36
37val after : 'a zipper -> 'a Sequence.t
38(** Return the sequence after the cursor *)
39
40val focus : 'a zipper -> 'a option
41(** Return the focus of the zipper, if any. *)
42
43val focus_or : 'a zipper -> default:'a -> 'a
44(** Return the focus of the zipper, or a user-provided default, otherwise. *)
45
46val history : 'a zipper -> 'a Sequence.t
47(** Returns the sequence of elements [pop]ped so far from the zipper. *)
48
49val is_far_left : 'a zipper -> bool
50(** Return whether the cursor is at the beginning of the zipper. *)
51
52val is_far_right : 'a zipper -> bool
53(** Return whether the cursor is at the end of the zipper. *)
54
55val is_empty : 'a zipper -> bool
56(** Return whether the zipper is empty. *)
57
58val left_length : 'a zipper -> int
59(** Return the number of elements before the cursor. *)
60
61val right_length : 'a zipper -> int
62(** Return the number of elements after the cursor. *)
63
64val length : 'a zipper -> int
65(** Return the length of the zipper. *)
66
67(** {1 Moving the cursor} *)
68
69val left : 'a zipper -> 'a zipper
70(** Move the cursor one step to the left, if possible.
71 Calling [left z],
72
73 - if [z] is [([3; 2; 1], [4; 5])], the result is [([2; 1], [3; 4; 5])],
74 - if [z] is [([], [1; 2; 3])], the result is [([], [1; 2; 3])].
75 *)
76
77val left_while : ('a -> bool) -> 'a zipper -> 'a zipper
78(** [left_while f z] moves the cursor in [z] to the left as long as the
79 predicate [f] is [true] when applied to the focus, or the left end
80 of the zipper is reached. *)
81
82val far_left : 'a zipper -> 'a zipper
83(** Move the cursor to the left, as much as possible. *)
84
85val right : 'a zipper -> 'a zipper
86(** Move the cursor one step to the right, if possible.
87 Calling [right z],
88
89 - if [z] is [([3; 2; 1], [4; 5])], the result is [([4; 3; 2; 1], [5])],
90 - if [z] is [([1; 2; 3], [])], the result is [([1; 2; 3], [])].
91 *)
92
93val right_while : ('a -> bool) -> 'a zipper -> 'a zipper
94(** [right_while f z] moves the cursor in [z] to the right as long as
95 the predicate [f] is [true] when applied to the focus, or the right
96 end of the zipper is reached. *)
97
98val far_right : 'a zipper -> 'a zipper
99(** Move the cursor to the right, as much as possible. *)
100
101val goto : int -> 'a zipper -> 'a zipper
102(** Move the cursor to a specific (absolute) position in the zipper.
103 Depending on the current position, it either moves the cursor
104 forward or backwards, without crossing the zipper boundaries. *)
105
106(** {1 Changes at the cursor} *)
107
108(** Zippers provide [O(1)] operations performed at the cursor position.
109 This involve [push]ing and [pop]ping elements before and after the
110 cursor. *)
111
112val pop_after : 'a zipper -> 'a zipper
113(** Remove the element at the cursor position, if any, and return the
114 modified zipper. Calling [pop_after z],
115
116 - if [z] is [([3; 2; 1], [4; 5])], the result is [([3; 2; 1], [5])],
117 - if [z] is [([1; 2; 3], [])], the result is [([1; 2; 3], [])].
118 *)
119
120val pop_before : 'a zipper -> 'a zipper
121(** Remove the element before the cursor, if any, and return the
122 modified zipper. Calling [pop_before z],
123
124 - if [z] is [([3; 2; 1], [4; 5])], the result is [([2; 1], [4, 5])],
125 - if [z] is [([], [1; 2; 3])], the result is [([], [1; 2; 3])].
126 *)
127
128val pop : 'a zipper -> 'a zipper
129(** [pop] is an alias for [pop_before]. *)
130
131val push_after : 'a -> 'a zipper -> 'a zipper
132(** Insert an element after the cursor.
133 Calling [push_after 0 z], if [z] is [([3; 2; 1], [4; 5])],
134 the result is [([3; 2; 1], [0; 4, 5]))], *)
135
136val push_before : 'a -> 'a zipper -> 'a zipper
137(** Insert an element before the cursor. Return the modified zipper.
138 Calling [push_before 0 z], if [z] is [([3; 2; 1], [4; 5])],
139 the result is [([0; 3; 2; 1], [4, 5]))]. *)
140
141val push : 'a -> 'a zipper -> 'a zipper
142(** [push] is an alias for [push_before]. *)
143
144val split : 'a zipper -> 'a zipper * 'a zipper
145(** [split z] splits the zipper in two. [([3; 2; 1], [4; 5])] becomes
146 [([3; 2; 1], []), ([], [4; 5])]. *)
147
148(** {1 Consuming zippers} *)
149
150(** Since zippers are based on sequences, iterating over zippers
151 terminates only when both sequences are finite.
152 Unless otherwise stated, these functions will iterate on the
153 elements before the cursor, first. *)
154
155val iter_before : ('a -> unit) -> 'a zipper -> unit
156(** [iter_before f z] will call [f x] for all [x], elements before the
157 cursor in [z].*)
158
159val iter_after : ('a -> unit) -> 'a zipper -> unit
160(** [iter_after f z] will call [f x] for all [x], elements after the
161 cursor in [z].*)
162
163val iter : ('a -> unit) -> 'a zipper -> unit
164(** [iter f z] is equivalent to [iter_before f z; iter_after f z] *)
165
166val for_all : ('a -> bool) -> 'a zipper -> bool
167(** [for_all p z] tests whether a predicate [p] is [true] for all
168 elements in a zipper. *)
169
170val exists : ('a -> bool) -> 'a zipper -> bool
171(** [exists p z] tests whether at least one element in the zipper is
172 [true] according to the predicate [p]. *)
173
174val find_before : ('a -> bool) -> 'a zipper -> 'a option
175(** [find_before p z] will return the first element before the cursor in
176 [z] satisfying the predicate [p], if any. *)
177
178val find_after : ('a -> bool) -> 'a zipper -> 'a option
179(** [find_after p z] will return the first element after the cursor in
180 [z] satisfying the predicate [p], if any. *)
181
182(** {1 Transforming zippers} *)
183
184(** Since zippers are based on sequences, the functions in this section
185 are lazy; i.e., resulting elements of the zipper are computed only
186 when demanded. *)
187
188val map_before : ('a -> 'a) -> 'a zipper -> 'a zipper
189(** Map a function over all elements before the cursor. *)
190
191val map_after : ('a -> 'a) -> 'a zipper -> 'a zipper
192(** Map a function over all elements after the cursor. *)
193
194val map_focus : ('a -> 'a) -> 'a zipper -> 'a zipper
195(** Map a function over the element focused by the cursor, if any. *)
196
197val map : ('a -> 'a) -> 'a zipper -> 'a zipper
198(** Map a function over all elements of a zipper. *)
199
200val mapi_before : (int -> 'a -> 'a) -> 'a zipper -> 'a zipper
201(** [mapi_before] is analogous to {!Zipper.map_before}, but the function
202 takes an index and an element.
203 The index indicates the distance of an element from the cursor. *)
204
205val mapi_after : (int -> 'a -> 'a) -> 'a zipper -> 'a zipper
206(** [mapi_after] is analogous to {!Zipper.map_after}, but the function
207 takes an index and an element.
208 The index indicates the distance of an element from the cursor. *)
209
210val mapi : (int -> 'a -> 'a) -> 'a zipper -> 'a zipper
211(** [mapi] is analogous to {!Zipper.map}, but the function takes an
212 index and an element.
213 The index indicates the distance of an element from the cursor. *)
214
215val filter_before : ('a -> bool) -> 'a zipper -> 'a zipper
216(** [filter_before p z] filters the elements before the cursor in a
217 zipper [z] according to a predicate [p], i.e., keeping the elements
218 that satisfy the predicate. *)
219
220val filter_after : ('a -> bool) -> 'a zipper -> 'a zipper
221(** [filter_after p z] filters the elements after the cursor in a
222 zipper [z] according to a predicate [p], i.e., keeping the elements
223 that satisfy the predicate. *)
224
225val filter : ('a -> bool) -> 'a zipper -> 'a zipper
226(** [filter p z] filters the elements of the zipper [z] according to a
227 predicate [p], i.e., keeping the elements that satisfy the
228 predicate. *)
229
230val context_before : int -> 'a zipper -> 'a zipper
231(** [context_before n z] will limit the zipper [z] to [n] elements before
232 the cursor. *)
233
234val context_after : int -> 'a zipper -> 'a zipper
235(** [context_after n z] will limit the zipper [z] to [n] elements after
236 the cursor. *)
237
238val context : b:int -> ?a:int -> 'a zipper -> 'a zipper
239(** [context ~b ~a z] will limit the zipper [z] to [b] elements before
240 the cursor and [a] elements after the cursor. When [a] is not
241 provided, it defaults to [b]. *)
242
243val clear_history : 'a zipper -> 'a zipper
244(** Clear the history of the zipper. See {!Zipper.history}. *)
245
246(** {1 Zippers and sequences} *)
247
248val of_seq : 'a Sequence.t -> 'a zipper
249(** Turn a sequence into a zipper with the cursor at the beginning. *)
250
251val to_seq : 'a zipper -> 'a Sequence.t
252(** Return the zipper as a sequence.
253 Calling [to_seq z], with [z] being [([3; 2; 1], [4; 5])], results in
254 [[1; 2; 3; 4; 5]]. *)
255
256val window : from:int -> len:int -> 'a zipper -> 'a Sequence.t
257(** [windows from len z] returns a sequence containing [len] elements
258 starting from [from]. *)