-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathzipper.ml
73 lines (63 loc) · 2.18 KB
/
zipper.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
(** Translated from the Scala code in Romain Edelmann's PhD thesis:
https://infoscience.epfl.ch/server/api/core/bitstreams/4fcb9f0f-7ac1-484f-823c-c19de39dd9ff/content
(section 2.5) *)
(** Datatype for binary trees *)
type 'a tree =
| Leaf of 'a
| Branch of 'a tree * 'a tree
(** The context represents the path taken to reach current subtree in focus *)
type 'a context =
| Empty
| InLeft of 'a tree * 'a context (* right tree and parent context *)
| InRight of 'a tree * 'a context (* left tree and parent context *)
(** A Zipper consists of a focused tree and a context *)
type 'a zipper = {
focus: 'a tree;
context: 'a context;
}
(** Helper to create a zipper *)
let focus (tree : 'a tree) : 'a zipper = {
focus = tree;
context = Empty;
}
(** Moves the focus to the parent node (constant-time) *)
let move_up (zipper : 'a zipper) : 'a zipper =
match zipper.context with
| Empty -> zipper
| InLeft (right, parent) ->
{ focus = Branch (zipper.focus, right);
context = parent }
| InRight (left, parent) ->
{ focus = Branch (left, zipper.focus);
context = parent }
(** Reconstruct the full tree from a zipper *)
let rec unfocus (zipper : 'a zipper) : 'a tree =
match zipper.context with
| Empty -> zipper.focus
| InLeft (right, parent) ->
unfocus {
focus = Branch (zipper.focus, right);
context = parent
}
| InRight (left, parent) ->
unfocus {
focus = Branch (left, zipper.focus);
context = parent
}
(** Moves the focus to the left child if possible (constant-time) *)
let move_left (zipper : 'a zipper) : 'a zipper =
match zipper.focus with
| Leaf _ -> zipper
| Branch (left, right) ->
{ focus = left;
context = InLeft (right, zipper.context) }
(** Moves the focus to the right child if possible (constant-time) *)
let move_right (zipper : 'a zipper) : 'a zipper =
match zipper.focus with
| Leaf _ -> zipper
| Branch (left, right) ->
{ focus = right;
context = InRight (left, zipper.context) }
(** Replaces the focus with a new tree *)
let replace_focus (zipper : 'a zipper) (new_focus : 'a tree) : 'a zipper =
{ zipper with focus = new_focus }