diff options
| author | Federico Igne <undyamon@disroot.org> | 2024-01-28 23:41:50 +0100 |
|---|---|---|
| committer | Federico Igne <undyamon@disroot.org> | 2024-01-28 23:41:50 +0100 |
| commit | 633fb26ed21f7208517aa29dbaab9f0cf3bb2047 (patch) | |
| tree | 2b6ae4402b61a03886f527355a9b480900598bdf /lib/tipper.ml | |
| parent | 05e1cc51b2fb0824580925b55319377305105c44 (diff) | |
| download | sandy-633fb26ed21f7208517aa29dbaab9f0cf3bb2047.tar.gz sandy-633fb26ed21f7208517aa29dbaab9f0cf3bb2047.zip | |
feat: add generic tree zipper data structure
Diffstat (limited to 'lib/tipper.ml')
| -rw-r--r-- | lib/tipper.ml | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/lib/tipper.ml b/lib/tipper.ml new file mode 100644 index 0000000..bf09bb9 --- /dev/null +++ b/lib/tipper.ml | |||
| @@ -0,0 +1,45 @@ | |||
| 1 | (* Module [Tipper]: functional tree zippers *) | ||
| 2 | |||
| 3 | open Base | ||
| 4 | |||
| 5 | type !+'a tipper = { | ||
| 6 | elt : 'a; | ||
| 7 | parent : 'a tipper option; | ||
| 8 | children : 'a tipper Zipper.t; | ||
| 9 | } | ||
| 10 | |||
| 11 | type !+'a t = 'a tipper | ||
| 12 | |||
| 13 | let create a = { elt = a; parent = None; children = Zipper.empty } | ||
| 14 | let focus t = t.elt | ||
| 15 | let is_root t = Option.(t.parent |> is_none) | ||
| 16 | let is_leaf t = Zipper.(t.children |> is_empty) | ||
| 17 | let is_far_left t = Zipper.(t.children |> is_far_left) | ||
| 18 | let is_far_right t = Zipper.(t.children |> is_far_right ~by_one:true) | ||
| 19 | let left t = { t with children = Zipper.left t.children } | ||
| 20 | let far_left t = { t with children = Zipper.far_left t.children } | ||
| 21 | let right t = { t with children = Zipper.right ~by_one:true t.children } | ||
| 22 | let far_right t = { t with children = Zipper.far_right ~by_one:true t.children } | ||
| 23 | let set_focus a t = { t with elt = a } | ||
| 24 | let push t1 t2 = { t2 with children = Zipper.push t1 t2.children } | ||
| 25 | |||
| 26 | let pop t = | ||
| 27 | let s, cs = Zipper.pop t.children in | ||
| 28 | (Sequence.hd s, { t with children = cs }) | ||
| 29 | |||
| 30 | let up t = Option.(map ~f:(push t) t.parent |> value ~default:t) | ||
| 31 | |||
| 32 | let rec up_while ~f t = | ||
| 33 | if (not (is_root t)) && f t then t |> up |> up_while ~f else t | ||
| 34 | |||
| 35 | let root t = up_while ~f:(fun n -> not (is_root n)) t | ||
| 36 | |||
| 37 | let down t = | ||
| 38 | match pop t with None, _ -> t | Some c, p -> { c with parent = Some p } | ||
| 39 | |||
| 40 | let rec fold ~a ~f t = | ||
| 41 | let a = f a t in | ||
| 42 | if is_leaf t then | ||
| 43 | let t = up_while ~f:is_far_right t in | ||
| 44 | if is_root t && is_far_right t then a else fold ~a ~f (t |> right |> down) | ||
| 45 | else fold ~a ~f (t |> far_left |> down) | ||
