Skip to content

Instantly share code, notes, and snippets.

@aschiavon91
Created April 12, 2021 15:26
Show Gist options
  • Select an option

  • Save aschiavon91/5c33db2e2d35e310e0aaebe5c4f66513 to your computer and use it in GitHub Desktop.

Select an option

Save aschiavon91/5c33db2e2d35e310e0aaebe5c4f66513 to your computer and use it in GitHub Desktop.
defmodule Zipper do
defstruct node: nil, focus: []
@type t :: %__MODULE__{node: BinTree.t(), focus: list({:left | :right, BinTree.t()})}
@doc """
Get a zipper focused on the root node.
"""
@spec from_tree(BinTree.t()) :: Zipper.t()
def from_tree(bin_tree), do: %__MODULE__{node: bin_tree}
@doc """
Get the complete tree from a zipper.
"""
@spec to_tree(Zipper.t()) :: BinTree.t()
def to_tree(%__MODULE__{node: node, focus: []}), do: node
def to_tree(%__MODULE__{} = zipper), do: zipper |> up() |> to_tree()
@doc """
Get the value of the focus node.
"""
@spec value(Zipper.t()) :: any
def value(%__MODULE__{node: %BinTree{value: value}}), do: value
@doc """
Get the left child of the focus node, if any.
"""
@spec left(Zipper.t()) :: Zipper.t() | nil
def left(%__MODULE__{node: %BinTree{left: nil}}), do: nil
def left(%__MODULE__{node: %BinTree{left: left} = node, focus: focus}),
do: %__MODULE__{node: left, focus: [{:left, node} | focus]}
@doc """
Get the right child of the focus node, if any.
"""
@spec right(Zipper.t()) :: Zipper.t() | nil
def right(%__MODULE__{node: %BinTree{right: nil}}), do: nil
def right(%__MODULE__{node: %BinTree{right: right} = node, focus: focus}),
do: %__MODULE__{node: right, focus: [{:right, node} | focus]}
@doc """
Get the parent of the focus node, if any.
"""
@spec up(Zipper.t()) :: Zipper.t() | nil
def up(%__MODULE__{focus: []}), do: nil
def up(%__MODULE__{focus: [{branch, parent} | focus], node: node}),
do: %__MODULE__{node: Map.put(parent, branch, node), focus: focus}
@doc """
Set the value of the focus node.
"""
@spec set_value(Zipper.t(), any) :: Zipper.t()
def set_value(%__MODULE__{node: node} = zipper, value),
do: %__MODULE__{zipper | node: %BinTree{node | value: value}}
@doc """
Replace the left child tree of the focus node.
"""
@spec set_left(Zipper.t(), BinTree.t() | nil) :: Zipper.t()
def set_left(%__MODULE__{node: node} = zipper, left),
do: %__MODULE__{zipper | node: %BinTree{node | left: left}}
@doc """
Replace the right child tree of the focus node.
"""
@spec set_right(Zipper.t(), BinTree.t() | nil) :: Zipper.t()
def set_right(%__MODULE__{node: node} = zipper, right),
do: %__MODULE__{zipper | node: %BinTree{node | right: right}}
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment