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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
open Base
open Zipper_types
module type Basic_cell = sig
type 'a t [@@deriving sexp]
val make : 'a -> 'a t
val data : 'a t -> 'a
val of_data_list : 'a list -> 'a t list
val to_data_list : 'a t list -> 'a list
include Travesty.Traversable_types.S1 with type 'a t := 'a t
end
let rev_transfer amount ~src ~dst =
if Int.(List.length src < amount) then None
else
let to_transfer, src' = List.split_n src amount in
let dst' = List.rev_append to_transfer dst in
Some (src', dst')
module Make (Cell : Basic_cell) = struct
type 'a t = {left: 'a Cell.t list; right: 'a Cell.t list}
[@@deriving fields, sexp]
let make ~left ~right =
{left= Cell.of_data_list left; right= Cell.of_data_list right}
let of_list lst = make ~left:[] ~right:lst
let left_list zipper = Cell.to_data_list (left zipper)
let right_list zipper = Cell.to_data_list (right zipper)
let to_list zipper = List.rev_append (left_list zipper) (right_list zipper)
let head zipper = List.hd (right zipper)
let set_head_cell_on_right right new_head =
match (right, new_head) with
| [], None -> []
| [], Some head' -> [head']
| _ :: rest, None -> rest
| _ :: rest, Some head' -> head' :: rest
let set_head_cell zipper new_head =
{zipper with right= set_head_cell_on_right zipper.right new_head}
let push zipper ~value =
{zipper with right= Cell.make value :: zipper.right}
let left_length zipper = List.length zipper.left
let right_length zipper = List.length zipper.right
let is_at_start zipper = List.is_empty zipper.left
let is_at_end zipper = List.is_empty zipper.right
module On_monad_base (M : Monad.S) = struct
module CM = Cell.On_monad (M)
module CO = Cell.On_monad (Option)
let pop_m zipper ~on_empty =
match zipper.right with
| [] -> on_empty zipper
| x :: xs -> M.return (Cell.data x, {zipper with right= xs})
end
module On_option_base = On_monad_base (Option)
let pop_opt zipper = On_option_base.pop_m ~on_empty:(Fn.const None) zipper
let peek_opt ?(steps = 0) zipper =
let open Option.Let_syntax in
let%map cell =
if steps < 0 then List.nth zipper.left (Int.abs steps - 1)
else List.nth zipper.right steps
in
Cell.data cell
module On_monad (M : Monad.S) = struct
include On_monad_base (M)
let peek_m ?steps zipper ~on_empty =
match peek_opt ?steps zipper with
| Some v -> M.return v
| None -> on_empty zipper
let step_m ?(steps = 1) zipper ~on_empty =
let amount = Int.abs steps in
match Ordering.of_int (Int.compare steps 0) with
| Less -> (
match rev_transfer amount ~src:zipper.left ~dst:zipper.right with
| Some (l, r) -> M.return {left= l; right= r}
| None -> on_empty zipper )
| Equal -> M.return zipper
| Greater -> (
match rev_transfer amount ~src:zipper.right ~dst:zipper.left with
| Some (r, l) -> M.return {left= l; right= r}
| None -> on_empty zipper )
let push_left_m zipper ~value ~on_empty =
push zipper ~value |> step_m ~on_empty
let map_m_head_cell zipper ~f ~on_empty =
match head zipper with
| None -> on_empty zipper
| Some h -> M.(f h >>| set_head_cell zipper)
let map_m_head zipper ~f ~on_empty =
map_m_head_cell zipper
~f:M.(fun h -> CM.map_m ~f h >>| CO.sequence_m)
~on_empty
end
module On_ident = On_monad (Monad.Ident)
module On_error = On_monad (Or_error)
module On_option = On_monad (Option)
let to_two_lists zipper = (left_list zipper, right_list zipper)
let map_head = On_ident.map_m_head ~on_empty:Fn.id
let pop zipper =
On_error.pop_m zipper ~on_empty:(fun _ ->
Or_error.error_string "Tried to pop an exhausted zipper" )
let step ?steps zipper =
On_error.step_m ?steps zipper ~on_empty:(fun zipper ->
Or_error.error_s
[%message
"Zipper stepping went out of bounds"
~steps:(Option.value ~default:1 steps : int)
~left_bound:(left_length zipper : int)
~right_bound:(right_length zipper : int)] )
let push_left = On_ident.push_left_m ~on_empty:(fun _ -> assert false)
end
module Plain_cell : Basic_cell = struct
include Singleton
let make = Fn.id
let data = Fn.id
let of_data_list = Fn.id
let to_data_list = Fn.id
end
module Plain : S = Make (Plain_cell)
module Make_marked_cell (B : Basic_mark) = struct
module Mark = struct
module M = struct
include B
include Comparator.Make (B)
end
include M
module Set = struct
type t = Set.M(M).t [@@deriving sexp]
end
end
(** ['a t] is the type of one cell. Each cell contains the data at the
given zipper location, as well as any marks that have been attached to
the cell for later recall. *)
type 'a t = {data: 'a; marks: Mark.Set.t} [@@deriving fields, sexp]
let make data = {data; marks= Set.empty (module Mark)}
let of_data_list = List.map ~f:make
let to_data_list = List.map ~f:data
let mark cell ~mark = {cell with marks= Set.add cell.marks mark}
module T = Travesty.Traversable.Make1 (struct
type nonrec 'a t = 'a t
module On (M : Applicative.S) = struct
let map_m cell ~f = M.(f cell.data >>| fun d -> {cell with data= d})
end
end)
include (T : module type of T with type 'a t := 'a t)
end
module Make_marked (Mark : Basic_mark) = struct
module Cell = Make_marked_cell (Mark)
module Main = Make (Cell)
include (Main : S_non_monadic with type 'a t = 'a Main.t)
module On_monad (M : Monad.S) = struct
include Main.On_monad (M)
let mark_m zipper ~mark ~on_empty =
map_m_head_cell zipper
~f:(fun h -> M.return (Some (Cell.mark ~mark h)))
~on_empty
let recall_m zipper ~mark ~on_empty =
let rec mu zipper' =
match List.hd zipper'.Main.right with
| Some h when Set.mem (Cell.marks h) mark -> M.return zipper'
| Some _ | None -> M.(step_m ~steps:(-1) zipper' ~on_empty >>= mu)
in
mu zipper
let delete_to_mark_m zipper ~mark ~on_empty =
let open M.Let_syntax in
let%map recalled_zipper = recall_m zipper ~mark ~on_empty in
let amount_to_delete =
left_length zipper - left_length recalled_zipper
in
{zipper with left= List.drop zipper.left amount_to_delete}
let rec fold_m_until zipper ~f ~init ~finish =
let open M.Let_syntax in
match pop_opt zipper with
| None -> finish init zipper
| Some (hd, zipper') -> (
match%bind f init hd zipper' with
| `Stop final -> M.return final
| `Drop accum -> fold_m_until zipper' ~f ~init:accum ~finish
| `Mark (mark, hd', accum) ->
push zipper' ~value:hd'
|> mark_m ~mark ~on_empty:M.return
>>= step_m ~on_empty:M.return
>>= fold_m_until ~f ~init:accum ~finish
| `Swap (hd', accum) ->
push_left_m zipper' ~value:hd' ~on_empty:M.return
>>= fold_m_until ~f ~init:accum ~finish )
end
module On_ident = On_monad (Monad.Ident)
module On_error = On_monad (Or_error)
module On_option = On_monad (Option)
let mark zipper ~mark =
On_error.mark_m zipper ~mark ~on_empty:(fun _ ->
Or_error.error_string "Tried to mark an exhausted zipper" )
let mark_not_found mark =
Or_error.error_s
[%message "Couldn't find requested mark" ~mark:(mark : Mark.t)]
let recall zipper ~mark =
On_error.recall_m zipper ~mark ~on_empty:(fun _ -> mark_not_found mark)
let delete_to_mark zipper ~mark =
On_error.delete_to_mark_m zipper ~mark ~on_empty:(fun _ ->
mark_not_found mark )
let fold_until = On_ident.fold_m_until
end
module Int_mark_zipper : S_marked with type mark := int = Make_marked (Int)