Packages

A functional zipper library for Gleam. This library provides zipper implementations for common data structures like lists, binary trees, and rose trees.

Current section

Files

Jump to
gleamy_zipper src zipper@tree.erl
Raw

src/zipper@tree.erl

-module(zipper@tree).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/zipper/tree.gleam").
-export([from_standard_tree/1, to_standard_tree/1, from_tree/2, to_tree/2, get_value/1, get_standard_tree/1, get_tree/2, set_value/2, set_standard_tree/2, set_tree/3, update/2, map_focus/2, upsert/2, set_left/2, set_right/2, go_up/1, is_root/1, delete/1, delete_left/1, delete_right/1, go_left/1, go_right/1, go_to_root/1]).
-export_type([tree/1, adapter/2, zipper/1, choice/1]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" A functional zipper data structure for binary trees.\n"
"\n"
" This module provides tools to navigate and modify binary tree structures\n"
" efficiently. The zipper makes it easy to move up, down, and sideways\n"
" in a tree and to perform local modifications without traversing the\n"
" entire tree.\n"
"\n"
" Most navigation and local modification operations are $O(1)$. Operations\n"
" that convert from or to a full tree structure are $O(n)$, where $n$ is the\n"
" number of nodes in the tree. Reconstructing the tree by navigating to the\n"
" root is $O(d)$, where $d$ is the depth of the current focus.\n"
"\n"
" It supports both a standard `Tree` type and can be adapted to work with\n"
" any user-defined binary tree structure via an `Adapter`.\n"
"\n"
" ## Usage\n"
" ```gleam\n"
" import zipper/tree\n"
"\n"
" let my_tree =\n"
" tree.Node(1, tree.Node(2, tree.Leaf, tree.Leaf), tree.Node(3, tree.Leaf, tree.Leaf))\n"
"\n"
" let zipper = tree.from_standard_tree(my_tree)\n"
"\n"
" // Navigate and modify the tree\n"
" let assert Ok(zipper) = tree.go_left(zipper)\n"
" let assert Ok(zipper) = tree.set_value(zipper, 4)\n"
" let assert Ok(zipper) = tree.go_up(zipper)\n"
"\n"
" tree.to_standard_tree(zipper)\n"
" // => Node(1, Node(4, Leaf, Leaf), Node(3, Leaf, Leaf))\n"
" ```\n"
).
-type tree(EED) :: leaf | {node, EED, tree(EED), tree(EED)}.
-type adapter(EEE, EEF) :: {adapter,
fun((EEF) -> gleam@option:option(EEE)),
fun((EEF) -> {gleam@option:option(EEF), gleam@option:option(EEF)}),
fun((gleam@option:option(EEE), {gleam@option:option(EEF),
gleam@option:option(EEF)}) -> EEF)}.
-opaque zipper(EEG) :: {zipper, list(choice(EEG)), tree(EEG)}.
-type choice(EEH) :: {left, EEH, tree(EEH)} | {right, EEH, tree(EEH)}.
-file("src/zipper/tree.gleam", 107).
?DOC(
" Creates a zipper from a standard binary tree.\n"
"\n"
" ## Examples\n"
" ```gleam\n"
" let tree = Node(1, Leaf, Leaf)\n"
" let zipper = from_standard_tree(tree)\n"
" ```\n"
).
-spec from_standard_tree(tree(EEI)) -> zipper(EEI).
from_standard_tree(Tree) ->
{zipper, [], Tree}.
-file("src/zipper/tree.gleam", 123).
?DOC(
" Converts a zipper back to a standard binary tree.\n"
"\n"
" This function reconstructs the original tree by walking back up\n"
" the navigation path and rebuilding the tree structure.\n"
"\n"
" ## Examples\n"
" ```gleam\n"
" let tree = Node(1, Leaf, Leaf)\n"
" let zipper = from_standard_tree(tree)\n"
" to_standard_tree(zipper)\n"
" // => Node(1, Leaf, Leaf)\n"
" ```\n"
).
-spec to_standard_tree(zipper(EEL)) -> tree(EEL).
to_standard_tree(Zipper) ->
case Zipper of
{zipper, [], Focus} ->
Focus;
{zipper, [{left, Value, Sibling} | Thread], Focus@1} ->
to_standard_tree({zipper, Thread, {node, Value, Focus@1, Sibling}});
{zipper, [{right, Value@1, Sibling@1} | Thread@1], Focus@2} ->
to_standard_tree(
{zipper, Thread@1, {node, Value@1, Sibling@1, Focus@2}}
)
end.
-file("src/zipper/tree.gleam", 143).
?DOC(
" Converts a user-defined tree to a standard binary tree using an adapter.\n"
"\n"
" This internal function recursively converts a user tree structure to the\n"
" standard tree representation used by the zipper.\n"
).
-spec user_tree_to_standard_tree(EEO, adapter(EEP, EEO)) -> tree(EEP).
user_tree_to_standard_tree(Users_tree, Adapter) ->
Value = (erlang:element(2, Adapter))(Users_tree),
Children = (erlang:element(3, Adapter))(Users_tree),
case {Value, Children} of
{none, _} ->
leaf;
{{some, Value@1}, {none, none}} ->
{node, Value@1, leaf, leaf};
{{some, Value@2}, {{some, Left}, none}} ->
{node, Value@2, user_tree_to_standard_tree(Left, Adapter), leaf};
{{some, Value@3}, {none, {some, Right}}} ->
{node, Value@3, leaf, user_tree_to_standard_tree(Right, Adapter)};
{{some, Value@4}, {{some, Left@1}, {some, Right@1}}} ->
{node,
Value@4,
user_tree_to_standard_tree(Left@1, Adapter),
user_tree_to_standard_tree(Right@1, Adapter)}
end.
-file("src/zipper/tree.gleam", 180).
?DOC(
" Creates a zipper from a user-defined tree using an adapter.\n"
"\n"
" ## Examples\n"
" ```gleam\n"
" // Given a user-defined tree `my_tree` and a corresponding `adapter`:\n"
" let zipper = from_tree(my_tree, adapter)\n"
"\n"
" // The zipper can now be navigated and modified.\n"
" get_value(zipper)\n"
" // => Ok(root_value)\n"
" ```\n"
).
-spec from_tree(EET, adapter(EEU, EET)) -> zipper(EEU).
from_tree(Users_tree, Adapter) ->
_pipe = user_tree_to_standard_tree(Users_tree, Adapter),
from_standard_tree(_pipe).
-file("src/zipper/tree.gleam", 192).
?DOC(
" Converts a standard binary tree to a user-defined tree using an adapter.\n"
"\n"
" This internal function converts the standard tree representation back to\n"
" the user's tree structure using the provided adapter.\n"
).
-spec standard_tree_to_user_tree(tree(EEY), adapter(EEY, EFA)) -> EFA.
standard_tree_to_user_tree(Tree, Adapter) ->
{Value@4, Children} = case Tree of
leaf ->
{none, {none, none}};
{node, Value, leaf, leaf} ->
{{some, Value}, {none, none}};
{node, Value@1, Left, leaf} ->
{{some, Value@1},
{{some, standard_tree_to_user_tree(Left, Adapter)}, none}};
{node, Value@2, leaf, Right} ->
{{some, Value@2},
{none, {some, standard_tree_to_user_tree(Right, Adapter)}}};
{node, Value@3, Left@1, Right@1} ->
{{some, Value@3},
{{some, standard_tree_to_user_tree(Left@1, Adapter)},
{some, standard_tree_to_user_tree(Right@1, Adapter)}}}
end,
(erlang:element(4, Adapter))(Value@4, Children).
-file("src/zipper/tree.gleam", 227).
?DOC(
" Converts a zipper to a user-defined tree using an adapter.\n"
"\n"
" ## Examples\n"
" ```gleam\n"
" // Given a `zipper` and a corresponding `adapter` for a custom tree type:\n"
" let my_tree = to_tree(zipper, adapter)\n"
"\n"
" // `my_tree` is now an instance of the custom tree type.\n"
" ```\n"
).
-spec to_tree(zipper(EFD), adapter(EFD, EFF)) -> EFF.
to_tree(Zipper, Adapter) ->
_pipe = to_standard_tree(Zipper),
standard_tree_to_user_tree(_pipe, Adapter).
-file("src/zipper/tree.gleam", 247).
?DOC(
" Gets the value of the current focus node.\n"
"\n"
" Returns `Ok(value)` if the focus is a node with a value,\n"
" or `Error(Nil)` if the focus is a leaf node.\n"
"\n"
" ## Examples\n"
" ```gleam\n"
" let node_zipper = from_standard_tree(Node(42, Leaf, Leaf))\n"
" get_value(node_zipper)\n"
" // => Ok(42)\n"
"\n"
" let leaf_zipper = from_standard_tree(Leaf)\n"
" get_value(leaf_zipper)\n"
" // => Error(Nil)\n"
" ```\n"
).
-spec get_value(zipper(EFI)) -> {ok, EFI} | {error, nil}.
get_value(Zipper) ->
case Zipper of
{zipper, _, leaf} ->
{error, nil};
{zipper, _, {node, Value, _, _}} ->
{ok, Value}
end.
-file("src/zipper/tree.gleam", 263).
?DOC(
" Gets the current focus subtree as a standard tree.\n"
"\n"
" ## Examples\n"
" ```gleam\n"
" let tree = Node(1, Leaf, Leaf)\n"
" let zipper = from_standard_tree(tree)\n"
" get_standard_tree(zipper)\n"
" // => Node(1, Leaf, Leaf)\n"
" ```\n"
).
-spec get_standard_tree(zipper(EFM)) -> tree(EFM).
get_standard_tree(Zipper) ->
erlang:element(3, Zipper).
-file("src/zipper/tree.gleam", 276).
?DOC(
" Gets the current focus subtree as a user-defined tree using an adapter.\n"
"\n"
" ## Examples\n"
" ```gleam\n"
" // Given a `zipper` and a corresponding `adapter` for a custom tree type:\n"
" let focused_subtree = get_tree(zipper, adapter)\n"
"\n"
" // `focused_subtree` is an instance of the custom tree type.\n"
" ```\n"
).
-spec get_tree(zipper(EFP), adapter(EFP, EFR)) -> EFR.
get_tree(Zipper, Adapter) ->
_pipe = get_standard_tree(Zipper),
standard_tree_to_user_tree(_pipe, Adapter).
-file("src/zipper/tree.gleam", 298).
?DOC(
" Sets the value of the current focus node.\n"
"\n"
" Returns `Ok(zipper)` with the updated value if the focus is a node,\n"
" or `Error(Nil)` if the focus is a leaf node.\n"
"\n"
" ## Examples\n"
" ```gleam\n"
" let zipper = from_standard_tree(Node(1, Leaf, Leaf))\n"
" case set_value(zipper, 42) {\n"
" Ok(zipper) -> get_value(zipper)\n"
" _ -> Error(Nil)\n"
" }\n"
" // => Ok(42)\n"
" ```\n"
).
-spec set_value(zipper(EFU), EFU) -> {ok, zipper(EFU)} | {error, nil}.
set_value(Zipper, Value) ->
case Zipper of
{zipper, _, leaf} ->
{error, nil};
{zipper, _, {node, _, _, _} = Focus} ->
{ok,
{zipper,
erlang:element(2, Zipper),
{node,
Value,
erlang:element(3, Focus),
erlang:element(4, Focus)}}}
end.
-file("src/zipper/tree.gleam", 319).
?DOC(
" Sets the current focus subtree to a new standard tree.\n"
"\n"
" This replaces the entire focused subtree with the provided tree.\n"
"\n"
" ## Examples\n"
" ```gleam\n"
" let zipper = from_standard_tree(Node(1, Leaf, Leaf))\n"
" let new_tree = Node(2, Leaf, Leaf)\n"
" let updated_zipper = set_standard_tree(zipper, new_tree)\n"
"\n"
" get_standard_tree(updated_zipper)\n"
" // => Node(2, Leaf, Leaf)\n"
" ```\n"
).
-spec set_standard_tree(zipper(EFZ), tree(EFZ)) -> zipper(EFZ).
set_standard_tree(Zipper, Tree) ->
{zipper, erlang:element(2, Zipper), Tree}.
-file("src/zipper/tree.gleam", 336).
?DOC(
" Sets the current focus subtree to a user-defined tree using an adapter.\n"
"\n"
" This replaces the entire focused subtree with the provided user tree\n"
" after converting it to the standard tree representation.\n"
"\n"
" ## Examples\n"
" ```gleam\n"
" // Given a `zipper`, a `my_subtree` of a user-defined type,\n"
" // and a corresponding `adapter`:\n"
" let updated_zipper = set_tree(zipper, my_subtree, adapter)\n"
"\n"
" // The focus of `updated_zipper` is now `my_subtree`.\n"
" ```\n"
).
-spec set_tree(zipper(EGD), EGF, adapter(EGD, EGF)) -> zipper(EGD).
set_tree(Zipper, Users_tree, Adapter) ->
Tree = user_tree_to_standard_tree(Users_tree, Adapter),
{zipper, erlang:element(2, Zipper), Tree}.
-file("src/zipper/tree.gleam", 359).
?DOC(
" Updates the value of the current focus node using a transformation function.\n"
"\n"
" Returns `Ok(zipper)` with the updated value if the focus is a node,\n"
" or `Error(Nil)` if the focus is a leaf node.\n"
"\n"
" ## Examples\n"
" ```gleam\n"
" let zipper = from_standard_tree(Node(1, Leaf, Leaf))\n"
" case update(zipper, fn(x) { x * 2 }) {\n"
" Ok(zipper) -> get_value(zipper)\n"
" _ -> Error(Nil)\n"
" }\n"
" // => Ok(2)\n"
" ```\n"
).
-spec update(zipper(EGJ), fun((EGJ) -> EGJ)) -> {ok, zipper(EGJ)} | {error, nil}.
update(Zipper, Updater) ->
case Zipper of
{zipper, _, leaf} ->
{error, nil};
{zipper, _, {node, Value, _, _} = Focus} ->
{ok,
{zipper,
erlang:element(2, Zipper),
{node,
Updater(Value),
erlang:element(3, Focus),
erlang:element(4, Focus)}}}
end.
-file("src/zipper/tree.gleam", 402).
?DOC(
" Maps the current focus node.\n"
"\n"
" Applies the updater function to the current focus subtree.\n"
"\n"
" ## Examples\n"
" ```gleam\n"
" let zipper = from_standard_tree(Leaf)\n"
" let updated_zipper = map_focus(zipper, fn(_) { Node(1, Leaf, Leaf) })\n"
"\n"
" get_value(updated_zipper)\n"
" // => Ok(1)\n"
" ```\n"
).
-spec map_focus(zipper(EGT), fun((tree(EGT)) -> tree(EGT))) -> zipper(EGT).
map_focus(Zipper, Updater) ->
{zipper, erlang:element(2, Zipper), Updater(erlang:element(3, Zipper))}.
-file("src/zipper/tree.gleam", 386).
?DOC(
" Upserts the current focus node.\n"
"\n"
" **Deprecated**: Use [`map_focus`](#map_focus) instead.\n"
"\n"
" Applies the updater function to the current focus subtree, allowing\n"
" both updates to existing nodes and insertion of new nodes.\n"
"\n"
" ## Examples\n"
" ```gleam\n"
" let zipper = from_standard_tree(Leaf)\n"
" let updated_zipper = upsert(zipper, fn(_) { Node(1, Leaf, Leaf) })\n"
"\n"
" get_value(updated_zipper)\n"
" // => Ok(1)\n"
" ```\n"
).
-spec upsert(zipper(EGO), fun((tree(EGO)) -> tree(EGO))) -> zipper(EGO).
upsert(Zipper, Updater) ->
map_focus(Zipper, Updater).
-file("src/zipper/tree.gleam", 422).
?DOC(
" Sets the left child of the current focus node.\n"
"\n"
" Returns `Ok(zipper)` with the updated left subtree if the focus is a node,\n"
" or `Error(Nil)` if the focus is a leaf node.\n"
"\n"
" ## Examples\n"
" ```gleam\n"
" let zipper = from_standard_tree(Node(1, Leaf, Leaf))\n"
" let assert Ok(zipper) = set_left(zipper, Node(2, Leaf, Leaf))\n"
"\n"
" get_standard_tree(zipper)\n"
" // => Node(1, Node(2, Leaf, Leaf), Leaf)\n"
" ```\n"
).
-spec set_left(zipper(EGY), tree(EGY)) -> {ok, zipper(EGY)} | {error, nil}.
set_left(Zipper, Left) ->
case Zipper of
{zipper, _, leaf} ->
{error, nil};
{zipper, _, {node, _, _, _} = Focus} ->
{ok,
{zipper,
erlang:element(2, Zipper),
{node,
erlang:element(2, Focus),
Left,
erlang:element(4, Focus)}}}
end.
-file("src/zipper/tree.gleam", 443).
?DOC(
" Sets the right child of the current focus node.\n"
"\n"
" Returns `Ok(zipper)` with the updated right subtree if the focus is a node,\n"
" or `Error(Nil)` if the focus is a leaf node.\n"
"\n"
" ## Examples\n"
" ```gleam\n"
" let zipper = from_standard_tree(Node(1, Leaf, Leaf))\n"
" let assert Ok(zipper) = set_right(zipper, Node(3, Leaf, Leaf))\n"
"\n"
" get_standard_tree(zipper)\n"
" // => Node(1, Leaf, Node(3, Leaf, Leaf))\n"
" ```\n"
).
-spec set_right(zipper(EHE), tree(EHE)) -> {ok, zipper(EHE)} | {error, nil}.
set_right(Zipper, Right) ->
case Zipper of
{zipper, _, leaf} ->
{error, nil};
{zipper, _, {node, _, _, _} = Focus} ->
{ok,
{zipper,
erlang:element(2, Zipper),
{node,
erlang:element(2, Focus),
erlang:element(3, Focus),
Right}}}
end.
-file("src/zipper/tree.gleam", 602).
?DOC(
" Moves the focus to the parent node.\n"
"\n"
" Returns `Ok(zipper)` focused on the parent node if not at root,\n"
" or `Error(Nil)` if already at the root (no parent).\n"
"\n"
" ## Examples\n"
" ```gleam\n"
" let zipper = from_standard_tree(Node(1, Node(2, Leaf, Leaf), Leaf))\n"
" let assert Ok(child_zipper) = go_left(zipper)\n"
"\n"
" case go_up(child_zipper) {\n"
" Ok(parent_zipper) -> get_value(parent_zipper)\n"
" _ -> Error(Nil)\n"
" }\n"
" // => Ok(1)\n"
" ```\n"
).
-spec go_up(zipper(EIL)) -> {ok, zipper(EIL)} | {error, nil}.
go_up(Zipper) ->
case Zipper of
{zipper, [], _} ->
{error, nil};
{zipper, [{left, Value, Right} | Thread], Focus} ->
{ok, {zipper, Thread, {node, Value, Focus, Right}}};
{zipper, [{right, Value@1, Left} | Thread@1], Focus@1} ->
{ok, {zipper, Thread@1, {node, Value@1, Left, Focus@1}}}
end.
-file("src/zipper/tree.gleam", 533).
?DOC(
" Checks if the current focus node is the root of the tree.\n"
"\n"
" Returns `True` if the zipper is at the root (no navigation history),\n"
" `False` otherwise.\n"
"\n"
" ## Examples\n"
" ```gleam\n"
" let zipper = from_standard_tree(Node(1, Node(2, Leaf, Leaf), Leaf))\n"
" is_root(zipper)\n"
" // => True\n"
"\n"
" let assert Ok(child_zipper) = go_left(zipper)\n"
" is_root(child_zipper)\n"
" // => False\n"
" ```\n"
).
-spec is_root(zipper(any())) -> boolean().
is_root(Zipper) ->
case Zipper of
{zipper, [], _} ->
true;
_ ->
false
end.
-file("src/zipper/tree.gleam", 467).
?DOC(
" Deletes the current focus node, replacing it with a leaf and moving to the parent.\n"
"\n"
" Returns `Ok(zipper)` focused on the parent node with the current node deleted,\n"
" or `Error(Nil)` if the focus is the root node (cannot delete root).\n"
"\n"
" ## Examples\n"
" ```gleam\n"
" let tree = Node(1, Node(2, Leaf, Leaf), Leaf)\n"
" let zipper = from_standard_tree(tree)\n"
"\n"
" let assert Ok(zipper) = go_left(zipper)\n"
" let assert Ok(zipper) = delete(zipper)\n"
"\n"
" to_standard_tree(zipper)\n"
" // => Node(1, Leaf, Leaf)\n"
" ```\n"
).
-spec delete(zipper(EHK)) -> {ok, zipper(EHK)} | {error, nil}.
delete(Zipper) ->
case is_root(Zipper) of
true ->
{error, nil};
false ->
_pipe = {zipper, erlang:element(2, Zipper), leaf},
go_up(_pipe)
end.
-file("src/zipper/tree.gleam", 488).
?DOC(
" Deletes the left child of the current focus node, replacing it with a leaf.\n"
"\n"
" Returns `Ok(zipper)` with the left child set to Leaf if the focus is a node,\n"
" or `Error(Nil)` if the focus is a leaf node.\n"
"\n"
" ## Examples\n"
" ```gleam\n"
" let tree = Node(1, Node(2, Leaf, Leaf), Leaf)\n"
" let zipper = from_standard_tree(tree)\n"
"\n"
" let assert Ok(deleted_zipper) = delete_left(zipper)\n"
" to_standard_tree(deleted_zipper)\n"
" // => Node(1, Leaf, Leaf)\n"
" ```\n"
).
-spec delete_left(zipper(EHP)) -> {ok, zipper(EHP)} | {error, nil}.
delete_left(Zipper) ->
case Zipper of
{zipper, _, leaf} ->
{error, nil};
{zipper, _, {node, _, _, _} = Focus} ->
{ok,
{zipper,
erlang:element(2, Zipper),
{node,
erlang:element(2, Focus),
leaf,
erlang:element(4, Focus)}}}
end.
-file("src/zipper/tree.gleam", 510).
?DOC(
" Deletes the right child of the current focus node, replacing it with a leaf.\n"
"\n"
" Returns `Ok(zipper)` with the right child set to Leaf if the focus is a node,\n"
" or `Error(Nil)` if the focus is a leaf node.\n"
"\n"
" ## Examples\n"
" ```gleam\n"
" let tree = Node(1, Leaf, Node(3, Leaf, Leaf))\n"
" let zipper = from_standard_tree(tree)\n"
"\n"
" let assert Ok(deleted_zipper) = delete_right(zipper)\n"
" to_standard_tree(deleted_zipper)\n"
" // => Node(1, Leaf, Leaf)\n"
" ```\n"
).
-spec delete_right(zipper(EHU)) -> {ok, zipper(EHU)} | {error, nil}.
delete_right(Zipper) ->
case Zipper of
{zipper, _, leaf} ->
{error, nil};
{zipper, _, {node, _, _, _} = Focus} ->
{ok,
{zipper,
erlang:element(2, Zipper),
{node,
erlang:element(2, Focus),
erlang:element(3, Focus),
leaf}}}
end.
-file("src/zipper/tree.gleam", 554).
?DOC(
" Moves the focus to the left child of the current node.\n"
"\n"
" Returns `Ok(zipper)` focused on the left child if it exists and is not a leaf,\n"
" or `Error(Nil)` if the left child doesn't exist or is a leaf.\n"
"\n"
" ## Examples\n"
" ```gleam\n"
" let zipper = from_standard_tree(Node(1, Node(2, Leaf, Leaf), Leaf))\n"
" case go_left(zipper) {\n"
" Ok(zipper) -> get_value(zipper)\n"
" _ -> Error(Nil)\n"
" }\n"
" // => Ok(2)\n"
" ```\n"
).
-spec go_left(zipper(EIB)) -> {ok, zipper(EIB)} | {error, nil}.
go_left(Zipper) ->
case Zipper of
{zipper, _, leaf} ->
{error, nil};
{zipper, _, {node, _, leaf, _}} ->
{error, nil};
{zipper, Thread, {node, Value, Left, Right}} ->
{ok, {zipper, [{left, Value, Right} | Thread], Left}}
end.
-file("src/zipper/tree.gleam", 577).
?DOC(
" Moves the focus to the right child of the current node.\n"
"\n"
" Returns `Ok(zipper)` focused on the right child if it exists and is not a leaf,\n"
" or `Error(Nil)` if the right child doesn't exist or is a leaf.\n"
"\n"
" ## Examples\n"
" ```gleam\n"
" let zipper = from_standard_tree(Node(1, Leaf, Node(3, Leaf, Leaf)))\n"
" case go_right(zipper) {\n"
" Ok(zipper) -> get_value(zipper)\n"
" _ -> Error(Nil)\n"
" }\n"
" // => Ok(3)\n"
" ```\n"
).
-spec go_right(zipper(EIG)) -> {ok, zipper(EIG)} | {error, nil}.
go_right(Zipper) ->
case Zipper of
{zipper, _, leaf} ->
{error, nil};
{zipper, _, {node, _, _, leaf}} ->
{error, nil};
{zipper, Thread, {node, Value, Left, Right}} ->
{ok, {zipper, [{right, Value, Left} | Thread], Right}}
end.
-file("src/zipper/tree.gleam", 629).
?DOC(
" Moves the focus back to the root of the tree.\n"
"\n"
" This operation is infallible: it always succeeds and returns a new zipper\n"
" focused at the root node while preserving the underlying tree structure.\n"
"\n"
" This function takes $O(d)$ time, where $d$ is the depth of the current focus.\n"
"\n"
" ## Examples\n"
" ```gleam\n"
" let zipper = from_standard_tree(Node(1, Node(2, Leaf, Leaf), Leaf))\n"
" let assert Ok(child_zipper) = go_left(zipper)\n"
" assert get_value(child_zipper) == Ok(2)\n"
"\n"
" let root_zipper = go_to_root(child_zipper)\n"
" assert is_root(root_zipper) == True\n"
" assert get_value(root_zipper) == Ok(1)\n"
" ```\n"
).
-spec go_to_root(zipper(EIQ)) -> zipper(EIQ).
go_to_root(Zipper) ->
case go_up(Zipper) of
{ok, Zipper@1} ->
go_to_root(Zipper@1);
{error, nil} ->
Zipper
end.