///|
/// Walk `root` (see `walk`) with an accumulator: `enter` and `leave` take
/// the current value and return the next one, in walk's callback order.
/// The result is the value after the last callback. The accumulator
/// belongs to the caller; fold does not copy it.
///
/// ```mbt check
/// test {
///   let root = @syntax.NodeRef::of_result(
///     @parser.parse_text("pub fn f() {\n  [[1]]\n}\n"),
///   )
///   // Count the expressions and find the deepest nesting.
///   let (count, _, deepest) = @syntax.fold(
///     root,
///     (0, 0, 0),
///     (acc, n) => {
///       let (count, depth, deepest) = acc
///       let count = count + (if n.category() == "expression" { 1 } else { 0 })
///       let depth = depth + 1
///       let deepest = if depth > deepest { depth } else { deepest }
///       ((count, depth, deepest), Continue)
///     },
///     leave=(acc, _) => (acc.0, acc.1 - 1, acc.2),
///   )
///   inspect(count, content="3")
///   inspect(deepest, content="6")
/// }
/// ```
pub fn[A] fold(
  root : NodeRef,
  init : A,
  enter : (A, NodeRef) -> (A, Control),
  leave~ : (A, NodeRef) -> A = (a, _) => a,
) -> A {
  let mut acc = init
  walk(
    root,
    n => {
      let (next, control) = enter(acc, n)
      acc = next
      control
    },
    leave=n => acc = leave(acc, n),
  )
  acc
}