Module Relude_TreeZipper

type t('a) = {
ancestors: list((list(Relude_Tree.t('a)), 'a, list(Relude_Tree.t('a)))),
leftSiblings: list(Relude_Tree.t('a)),
focus: 'a,
rightSiblings: list(Relude_Tree.t('a)),
children: list(Relude_Tree.t('a)),
};

A zipper for a non-empty multi-way/rose tree

The leftSiblings are stored in reverse order for O(1) sideways movements.

Based on the ideas/implementation from Tony Morris' talk here: http://data.tmorris.net/talks/zippers/bd054c210649101b84662c614fc45af3c27a5eef/zippers.pdf

let pure: 'a => t('a);

Creates a tree zipper containing a single item

let singleton: 'a => t('a);

Alias for pure

let make: a. list((list(Relude_Tree.t('a)), 'a, list(Relude_Tree.t('a)))) => list(Relude_Tree.t('a)) => 'a => list(Relude_Tree.t('a)) => list(Relude_Tree.t('a)) => t('a);

Constructs a tree zipper from parts

let makeWithLabels: a. ancestors:list((list(Relude_Tree.t('a)), 'a, list(Relude_Tree.t('a)))) => leftSiblings:list(Relude_Tree.t('a)) => focus:'a => rightSiblings:list(Relude_Tree.t('a)) => children:list(Relude_Tree.t('a)) => t('a);

Constructs a tree zipper from (labelled) parts

let fromTree: a. Relude_Tree.t('a) => t('a);

Converts a Tree into a Tree Zipper

let getAncestors: a. t('a) => list((list(Relude_Tree.t('a)), 'a, list(Relude_Tree.t('a))));

Gets the list of ancestor levels for the given TreeZipper

let getFocusValue: a. t('a) => 'a;

Gets the value at the focus of the TreeZipper

let tapFocusValue: a. ('a => unit) => t('a) => t('a);

Applies a side-effect function with the current focus value, and returns the zipper unchanged

let setFocusValue: a. 'a => t('a) => t('a);

Overwrites the focus with the given value

let modifyFocusValue: a. ('a => 'a) => t('a) => t('a);

Modifies the focus with the given function

let getFocusTree: a. t('a) => Relude_Tree.t('a);

Gets the value and children at the focus of the TreeZipper as a Tree

let getLeftSiblings: a. t('a) => list(Relude_Tree.t('a));

Gets the siblings to the left of the focus value, in reverse order. (the first item of the resulting list is the item that is immediately to the left of the focus).

let getLeftSiblingsInOrder: a. t('a) => list(Relude_Tree.t('a));

Gets the siblings to the left of the focus value, in order. (the first item of the resulting list is the item that is the leftmost sibling (furthest from focus))

let setLeftSiblings: a. list(Relude_Tree.t('a)) => t('a) => option(t('a));

Sets the left siblings from a reversed list (where the first item of the list should be closest to the focus)

let setLeftSiblingsFromInOrder: a. list(Relude_Tree.t('a)) => t('a) => option(t('a));

Sets the left siblings from an in-order list (where the first item of the list should be farthest from the focus)

let getRightSiblings: a. t('a) => list(Relude_Tree.t('a));

Gets the siblings to the right of the current focus

let setRightSiblings: a. list(Relude_Tree.t('a)) => t('a) => option(t('a));

Sets the right siblings from a reversed list (where the first item of the list should be closest to the focus)

let getChildren: a. t('a) => list(Relude_Tree.t('a));

Gets the children sub-trees of the current focus

let setChildren: a. list(Relude_Tree.t('a)) => t('a) => t('a);

Sets the children

let moveLeft: a. t('a) => option(t('a));

Moves the focus one sibling to the left (if possible)

let moveLeftWithClamp: a. t('a) => t('a);

Moves to the left, unless we are already at the leftmost item

let moveLeftToStart: a. t('a) => t('a);

Moves the focus as far as possible to the left

let moveLeftTimes: a. int => t('a) => option(t('a));

Moves left a number of times

let moveLeftTimesWithClamp: a. int => t('a) => t('a);

Move the focus to the left a number of times, stopping if the leftmost sibling is reached

let moveRight: a. t('a) => option(t('a));

Moves the focus one sibling to the right (if possible)

let moveRightWithClamp: a. t('a) => t('a);

Moves the zipper to the right one time, unless we are already at the rightmost item

let moveRightToEnd: a. t('a) => t('a);

Moves the focus as far as possible to the right

let moveRightTimes: a. int => t('a) => option(t('a));

Moves right a number of times

let moveRightTimesWithClamp: a. int => t('a) => t('a);

Move the focus to the right a number of times, stopping if the rightmost sibling is reached

let moveUp: a. t('a) => option(t('a));

Moves the focus up one level to the parent (if possible)

let moveUpWithClamp: a. t('a) => t('a);

Moves the zipper up a level, unless it's already at the top

let moveUpToTop: a. t('a) => t('a);

Moves the zipper to focus the top of the tree

let moveUpTimes: a. int => t('a) => option(t('a));

Moves the zipper up a number of times (if possible)

let moveUpTimesWithClamp: a. int => t('a) => t('a);

Moves the zipper up a number of times, stopping if the top is reached

let moveDown: a. t('a) => option(t('a));

Moves the focus down to the first child (if possible)

let moveDownWithClamp: a. t('a) => t('a);

Moves the zipper down one time, unless there are no children

let moveDownToBottom: a. t('a) => t('a);

Moves the zipper to focus the bottom of the tree (on the left-most child branches)

let moveDownTimes: a. int => t('a) => option(t('a));

Moves the focus down a number of times (if possible)

let moveDownTimesWithClamp: a. int => t('a) => t('a);

Moves the zipper down a number of times, stopping when we get as low as we can, staying on the left-most child branches.

type movement = [
| `Up(int)
| `UpWithClamp(int)
| `UpToTop
| `Down(int)
| `DownWithClamp(int)
| `DownToBottom
| `Left(int)
| `LeftWithClamp(int)
| `LeftToStart
| `Right(int)
| `RightWithClamp(int)
| `RightToEnd
];

Types of movements we can make in a TreeZipper

let moveOnceBy: a. movement => t('a) => option(t('a));

Applies a single movement command to a zipper

let moveBy: a. BsBastet.List.Foldable.t(movement) => t('a) => option(t('a));

Applies a list of movement commands to a zipper

let foldBy: a b. BsBastet.List.Foldable.t(movement) => ('b => 'a => 'b) => 'b => t('a) => option((t('a), 'b));

Applies a list of movement commands to a zipper and collects an accumulated value when visiting each new focus

let map: a b. ('a => 'b) => t('a) => t('b);

Converts a zipper of 'a to a zipper of 'b using a pure function

module Functor: BsBastet.Interface.FUNCTOR with type Functor.t('a) = t('a);
include { ... };
module BsFunctorExtensions: { ... };
let flipMap: Functor.t('a) => ('a => 'b) => Functor.t('b);
let void: Functor.t('a) => Functor.t(unit);
let voidRight: 'a => Functor.t('b) => Functor.t('a);
let voidLeft: Functor.t('a) => 'b => Functor.t('b);
let flap: Functor.t(('a => 'b)) => 'a => Functor.t('b);
let findInFocus: a. ('a => bool) => t('a) => option(t('a));
let findInFocusAndChildren: a. ('a => bool) => t('a) => option(t('a));

Finds a value in the curernt focus and recursively the children. Equivalent to a depth first search in the currently focused tree.

let findLeft: a. ?⁠checkFocus:bool => ('a => bool) => t('a) => option(t('a));

Attempts to find a value by searching the current focus and left siblings

let findRight: a. ?⁠checkFocus:bool => ('a => bool) => t('a) => option(t('a));

Attempts to find a value by searching the current focus and right siblings

let findLeftOrRight: a. ?⁠checkFocus:bool => ('a => bool) => t('a) => option(t('a));

Attempts to find a value by searching the current focus, then the left siblings from the focus outward, then the right siblings from the focus outward.

let findUp: a. ('a => bool) => t('a) => option(t('a));

Attempts to find a value by moving up a level, then searching left and right on the parent level, then progressing upward.

let findDown: a. ('a => bool) => t('a) => option(t('a));

Attempts to find a value by moving down a level, then searching left and right on the child level, then progressing downward.

let find: a. ('a => bool) => t('a) => option(t('a));

Attempts to find a value anywhere in the zipper, left/right/up/down

let insertTreeWithPushLeft: a. Relude_Tree.t('a) => t('a) => option(t('a));

Inserts a new tree, and pushes the current focus to the left

let insertWithPushLeft: a. 'a => t('a) => option(t('a));

Inserts a new value (singleton tree), and pushes the current focus to the left

let insertTreeWithPushRight: a. Relude_Tree.t('a) => t('a) => option(t('a));

Inserts a new tree, and pushes the current focus to the right

let insertWithPushRight: a. 'a => t('a) => option(t('a));

Inserts a new value (singleton tree), and pushes the current focus to the right

let deleteWithPullLeft: a. t('a) => option(t('a));

Deletes the tree at the focus, and pulls the left sibling into focus (if possible)

let deleteWithPullRight: a. t('a) => option(t('a));

Deletes the tree at the focus, and pulls the right sibling into focus (if possible)

let delete: a. t('a) => option(t('a));

Attempts to delete by deleting and pulling from the left. If there is no item on the left, it tries to pull from the right. If there is no item on the right, it moves the focus up a level, discarding the current focus and children.

let showBy: a. ('a => string) => t('a) => string;