Current section
Files
Jump to
Current section
Files
lib/zipper_list_protocols.ex
defimpl Inspect, for: ZipperList do
# Inspect sorts the keys alphabetically, but we want to represent it
# in human sensible order
def inspect(zipper, opts) do
import Inspect.Algebra
concat ["%ZipperList{left: ", to_doc(zipper.left, opts),
", cursor: ", to_doc(zipper.cursor, opts),
", right: ", to_doc(zipper.right, opts),
"}"]
end
end
defimpl Collectable, for: ZipperList do
def into(zipper) do
{zipper, &into/2}
end
defp into(zipper, {:cont, item}) do
ZipperList.push(zipper, item)
end
defp into(zipper, :done), do: zipper
defp into(_zipper, :halt), do: :ok
end
defimpl Enumerable, for: ZipperList do
@doc """
Returns the count of the items in the zipper, including the cursor position.
## Examples
iex> Enum.count(%ZipperList{left: [2, 1], right: [4], cursor: 3})
4
"""
def count(z = %ZipperList{}), do: {:ok, ZipperList.count(z)}
@doc """
Checks if the value is a member of the ZipperList, including the cursor position.
## Examples
iex> Enum.member?(%ZipperList{left: [1, 3, 5], cursor: 8, right: [2, 1]}, 5)
true
iex> Enum.member?(ZipperList.empty, "potato")
false
"""
def member?(%ZipperList{left: [], right: [], cursor: nil}, _), do: {:ok, false}
def member?(z = %ZipperList{}, value) do
{:ok, z.cursor == value || Enum.member?(z.right, value) || Enum.member?(z.left, value)}
end
@doc """
Reduce the ZipperList starting at the cursor and reducing right. Does not move
the cursor position. Use `ZipperList.cursor_start/1` if you want to start from
the beginning.
## Examples
iex> z = %ZipperList{left: [2, 1], cursor: 3, right: [4, 5]}
iex> Enumerable.reduce(z, {:cont, 0}, fn(z, acc) ->
...> {:cont, z.cursor + acc}
...>end)
{:done, 12}
"""
def reduce(%ZipperList{cursor: nil, right: []}, {:cont, acc}, _fun) do
{:done, acc}
end
def reduce(z = %ZipperList{}, {state, acc}, fun) do
case state do
:cont -> reduce(ZipperList.right(z), fun.(z, acc), fun)
:halt -> {:halted, acc}
:suspend -> {:suspended, acc, &reduce(z, &1, fun)}
end
end
end