View Source Hold.Zipper.List (hold v0.1.0)
An implementation of a Zipper over a list
Introductory Article: https://ferd.ca/yet-another-article-on-zippers.html
Supports being able to traverse a list both forwards and backwards while maintaining a focus on the current element much like a doubly-linked list. All while using functional immutable data structures and supporting O(1) lookup and traversal from focus.
So given the list [1, 2, 3, 4, 5]
we can imagine being able to "stop" on 3
and then backtrack or keep progressing forward.
(3)
2 4
1 5
Zipper.List also supports θ(1) updating the currently focused item.
Summary
Types
left
represents items to the left of the focus. right
is a list where the
head of it is the current focus and the rest is the items to the right of
focus.
Functions
Return zipper with focus on the first element.
Return currently focused element.
Return zipper with focus on the last element.
Move focus left, if possible.
Return whether an element to the right exists.
Move focus right, if possible.
Return whether an element to the right exists.
Updates the element which is currently focused.
Types
@type invalid_move() :: {:error, :invalid_move}
@type t(a) :: {left :: [a], right :: [a]}
left
represents items to the left of the focus. right
is a list where the
head of it is the current focus and the rest is the items to the right of
focus.
Functions
Return zipper with focus on the first element.
iex> zipper = Hold.Zipper.List.from_list([1, 2, 3, 4, 5])
iex> {:ok, zipper} = Hold.Zipper.List.right(zipper)
iex> {:ok, zipper} = Hold.Zipper.List.right(zipper)
iex> zipper = Hold.Zipper.List.first(zipper)
iex> Hold.Zipper.List.focus(zipper)
1
Return currently focused element.
iex> zipper = Hold.Zipper.List.from_list([1, 2, 3, 4, 5])
iex> Hold.Zipper.List.focus(zipper)
1
iex> zipper = Hold.Zipper.List.from_list([1, 2, 3, 4, 5])
iex> {:ok, zipper} = Hold.Zipper.List.right(zipper)
iex> Hold.Zipper.List.focus(zipper)
2
Return zipper with focus on the last element.
iex> zipper = Hold.Zipper.List.from_list([1, 2, 3, 4, 5])
iex> zipper = Hold.Zipper.List.last(zipper)
iex> Hold.Zipper.List.focus(zipper)
5
@spec left(t()) :: {:ok, t()} | Hold.Zipper.invalid_move()
Move focus left, if possible.
iex> zipper = Hold.Zipper.List.from_list([1, 2, 3, 4, 5])
iex> {:ok, zipper} = Hold.Zipper.List.right(zipper)
iex> {:ok, zipper} = Hold.Zipper.List.left(zipper)
iex> Hold.Zipper.List.focus(zipper)
1
iex> zipper = Hold.Zipper.List.from_list([1, 2, 3, 4, 5])
iex> Hold.Zipper.List.left(zipper)
{:error, :invalid_move}
Return whether an element to the right exists.
iex> zipper = Hold.Zipper.List.from_list([1, 2, 3, 4, 5])
iex> {:ok, zipper} = Hold.Zipper.List.right(zipper)
iex> Hold.Zipper.List.left?(zipper)
true
iex> zipper = Hold.Zipper.List.from_list([1, 2, 3, 4, 5])
iex> Hold.Zipper.List.left?(zipper)
false
@spec right(t()) :: {:ok, t()} | Hold.Zipper.invalid_move()
Move focus right, if possible.
iex> zipper = Hold.Zipper.List.from_list([1, 2, 3, 4, 5])
iex> {:ok, zipper} = Hold.Zipper.List.right(zipper)
iex> Hold.Zipper.List.focus(zipper)
2
iex> zipper = Hold.Zipper.List.from_list([1])
iex> Hold.Zipper.List.right(zipper)
{:error, :invalid_move}
Return whether an element to the right exists.
iex> zipper = Hold.Zipper.List.from_list([1, 2, 3, 4, 5])
iex> Hold.Zipper.List.right?(zipper)
true
iex> zipper = Hold.Zipper.List.from_list([1])
iex> Hold.Zipper.List.right?(zipper)
false
Updates the element which is currently focused.
iex> zipper = Hold.Zipper.List.from_list([1, 2, 3, 4, 5])
iex> {:ok, zipper} = Hold.Zipper.List.right(zipper)
iex> zipper = Hold.Zipper.List.update(zipper, 20)
iex> Hold.Zipper.List.to_list(zipper)
[1, 20, 3, 4, 5]