generic_tree.ml 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. open Base
  2. type ('a, 'l) tree =
  3. | Arm of 'a * ('a, 'l) tree list
  4. | Leaf of 'l
  5. type ('a, 'l) t = ('a, 'l) tree
  6. module type SHOW_EQ = sig
  7. type t
  8. val to_string : t -> string
  9. val equal : t -> t -> bool
  10. end
  11. module Make_show_eq(A: SHOW_EQ)(L: SHOW_EQ) = struct
  12. let rec to_string = function
  13. | Arm(a, ts) ->
  14. Printf.sprintf "%s[%s]"
  15. (A.to_string a)
  16. (String.concat ~sep:"; "
  17. (List.map ts ~f:to_string))
  18. | Leaf(l) ->
  19. L.to_string l
  20. let rec equal a b = match a, b with
  21. | Arm(a1, [t1]), Arm(a2, [t2]) -> A.equal a1 a2 && equal t1 t2
  22. | Arm(a1, ts1), Arm(a2, ts2) -> A.equal a1 a2 && List.equal ts1 ts2 ~equal
  23. | Leaf(l1), Leaf(l2) -> L.equal l1 l2
  24. | _, _ -> false
  25. end
  26. (*** zipper ***)
  27. type path = int list
  28. module Zipper = struct
  29. type ('a, 'l) t =
  30. { ctx : ('a, 'l) arm_ctx list
  31. ; foc : ('a, 'l) tree }
  32. and ('a, 'l) arm_ctx =
  33. { tag : 'a
  34. ; left_rev : ('a, 'l) tree list
  35. ; right : ('a, 'l) tree list }
  36. module Error = struct
  37. type t = Bad_index | Not_arm | No_parent
  38. let to_string = function
  39. | Bad_index -> "node index out of range"
  40. | Not_arm -> "cannot navigate to node"
  41. | No_parent -> "trying to navigate above root"
  42. let or_fail v = match v with
  43. | Ok(x) -> x
  44. | Error(e) -> failwith (to_string e)
  45. [@@ocaml.inline always]
  46. end
  47. (*** basics ***)
  48. let of_tree foc = { ctx = [] ; foc } [@@ocaml.inline always]
  49. let get {foc; _} = foc [@@ocaml.inline always]
  50. let set foc z = { z with foc } [@@ocaml.inline always]
  51. let modify ~f z = { z with foc = f z.foc } [@@ocaml.inline always]
  52. (*** movement ***)
  53. let up = function
  54. | { ctx = [] ; _ } -> Error(Error.No_parent)
  55. | { ctx = {tag;left_rev;right}::ctx ; foc } ->
  56. let foc = Arm(tag, List.rev_append left_rev (foc::right)) in
  57. Ok {ctx;foc}
  58. let down i = function
  59. | { ctx ; foc = Arm(tag, ts) } ->
  60. let rec split left_rev = function
  61. | (_, []) -> Error(Error.Bad_index)
  62. | (0, foc::right) -> Ok { foc ; ctx = {tag;left_rev;right}::ctx }
  63. | (i, t::ts) -> split (t::left_rev) (i - 1, ts)
  64. in
  65. if i < 0 then Error(Error.Bad_index)
  66. else split [] (i, ts)
  67. | _ ->
  68. Error(Error.Not_arm)
  69. let side amt = function
  70. | { ctx = [] ; _ } -> Error(Error.No_parent)
  71. | { ctx = {tag;left_rev;right}::ctx ; foc } ->
  72. let rec move = function
  73. | 0, left_rev, right, foc ->
  74. Ok { ctx = {tag;left_rev;right}::ctx ; foc }
  75. | i, t::left, right, foc when i < 0 ->
  76. move (i + 1, left, foc::right, t)
  77. | i, left, t::right, foc when i > 0 ->
  78. move (i - 1, foc::left, right, t)
  79. | _, _, _, _ ->
  80. Error(Error.Bad_index)
  81. in
  82. move (amt, left_rev, right, foc)
  83. let nav ?(prev=[]) ~targ z =
  84. let open Result.Monad_infix in
  85. (* move up the tree according to [p_up] then move down according to [p_down]. *)
  86. let ladder p_up p_down =
  87. List.fold_result p_up ~init:z ~f:(fun z _ -> up z) >>= fun z ->
  88. List.fold_result p_down ~init:z ~f:(fun z i -> down i z)
  89. in
  90. (* skip prefixes of the paths that are the same; move horizontally if the paths are
  91. the same up until the last index *)
  92. let rec elim_prefix = function
  93. | [i], [j] ->
  94. side (j - i) z
  95. | i::p1, j::p2 when Int.(i = j) ->
  96. elim_prefix (p1, p2)
  97. | p1, p2 ->
  98. ladder p1 p2
  99. in
  100. elim_prefix (prev, targ)
  101. let rec to_tree z =
  102. match up z with
  103. | Ok(z) -> to_tree z
  104. | Error(_) -> z.foc
  105. (*** "_exn" variants ***)
  106. let up_exn z = Error.or_fail (up z)
  107. let down_exn i z = Error.or_fail (down i z)
  108. let side_exn amt z = Error.or_fail (side amt z)
  109. let nav_exn ?prev ~targ z = Error.or_fail (nav ?prev ~targ z)
  110. end