diff options
Diffstat (limited to 'lib/zipper.mli')
-rw-r--r-- | lib/zipper.mli | 258 |
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 @@ | |||
1 | open 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 | |||
18 | type !+'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 | |||
28 | type !+'a t = 'a zipper | ||
29 | (** An alias for the ['a zipper] type. *) | ||
30 | |||
31 | val empty : 'a zipper | ||
32 | (** Return an empty zipper *) | ||
33 | |||
34 | val before : 'a zipper -> 'a Sequence.t | ||
35 | (** Return the sequence before the cursor *) | ||
36 | |||
37 | val after : 'a zipper -> 'a Sequence.t | ||
38 | (** Return the sequence after the cursor *) | ||
39 | |||
40 | val focus : 'a zipper -> 'a option | ||
41 | (** Return the focus of the zipper, if any. *) | ||
42 | |||
43 | val focus_or : 'a zipper -> default:'a -> 'a | ||
44 | (** Return the focus of the zipper, or a user-provided default, otherwise. *) | ||
45 | |||
46 | val history : 'a zipper -> 'a Sequence.t | ||
47 | (** Returns the sequence of elements [pop]ped so far from the zipper. *) | ||
48 | |||
49 | val is_far_left : 'a zipper -> bool | ||
50 | (** Return whether the cursor is at the beginning of the zipper. *) | ||
51 | |||
52 | val is_far_right : 'a zipper -> bool | ||
53 | (** Return whether the cursor is at the end of the zipper. *) | ||
54 | |||
55 | val is_empty : 'a zipper -> bool | ||
56 | (** Return whether the zipper is empty. *) | ||
57 | |||
58 | val left_length : 'a zipper -> int | ||
59 | (** Return the number of elements before the cursor. *) | ||
60 | |||
61 | val right_length : 'a zipper -> int | ||
62 | (** Return the number of elements after the cursor. *) | ||
63 | |||
64 | val length : 'a zipper -> int | ||
65 | (** Return the length of the zipper. *) | ||
66 | |||
67 | (** {1 Moving the cursor} *) | ||
68 | |||
69 | val 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 | |||
77 | val 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 | |||
82 | val far_left : 'a zipper -> 'a zipper | ||
83 | (** Move the cursor to the left, as much as possible. *) | ||
84 | |||
85 | val 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 | |||
93 | val 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 | |||
98 | val far_right : 'a zipper -> 'a zipper | ||
99 | (** Move the cursor to the right, as much as possible. *) | ||
100 | |||
101 | val 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 | |||
112 | val 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 | |||
120 | val 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 | |||
128 | val pop : 'a zipper -> 'a zipper | ||
129 | (** [pop] is an alias for [pop_before]. *) | ||
130 | |||
131 | val 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 | |||
136 | val 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 | |||
141 | val push : 'a -> 'a zipper -> 'a zipper | ||
142 | (** [push] is an alias for [push_before]. *) | ||
143 | |||
144 | val 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 | |||
155 | val 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 | |||
159 | val 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 | |||
163 | val iter : ('a -> unit) -> 'a zipper -> unit | ||
164 | (** [iter f z] is equivalent to [iter_before f z; iter_after f z] *) | ||
165 | |||
166 | val 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 | |||
170 | val 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 | |||
174 | val 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 | |||
178 | val 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 | |||
188 | val map_before : ('a -> 'a) -> 'a zipper -> 'a zipper | ||
189 | (** Map a function over all elements before the cursor. *) | ||
190 | |||
191 | val map_after : ('a -> 'a) -> 'a zipper -> 'a zipper | ||
192 | (** Map a function over all elements after the cursor. *) | ||
193 | |||
194 | val map_focus : ('a -> 'a) -> 'a zipper -> 'a zipper | ||
195 | (** Map a function over the element focused by the cursor, if any. *) | ||
196 | |||
197 | val map : ('a -> 'a) -> 'a zipper -> 'a zipper | ||
198 | (** Map a function over all elements of a zipper. *) | ||
199 | |||
200 | val 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 | |||
205 | val 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 | |||
210 | val 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 | |||
215 | val 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 | |||
220 | val 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 | |||
225 | val 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 | |||
230 | val 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 | |||
234 | val 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 | |||
238 | val 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 | |||
243 | val clear_history : 'a zipper -> 'a zipper | ||
244 | (** Clear the history of the zipper. See {!Zipper.history}. *) | ||
245 | |||
246 | (** {1 Zippers and sequences} *) | ||
247 | |||
248 | val of_seq : 'a Sequence.t -> 'a zipper | ||
249 | (** Turn a sequence into a zipper with the cursor at the beginning. *) | ||
250 | |||
251 | val 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 | |||
256 | val 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]. *) | ||