# Circular Lists (CList Module)
`CList` allow to work with circular lists. A circular lists is a finite list that can be traversed
as if it were infinite. This is possible because in a circular list, when you reach the end of the
list, you go back to the beginning and take the first element of the list as if it were next to
the last one. In other words, we could assume that a copy of the original list is inserted at the
end of the list, and so on ad infinitum.
Internally a `CList` is a map that store the *original list* (see below [original and current list](#module-original-and-current-list))
and a pointer indicating the current position in base 1 (as Erlang lists).
Although internally a `CList` is a map, its visual representation (IO.inspect) is:
```elixir
iex> CList.new([1, 2, 3, 4, 5])
#CList[1, 2, 3, 4, 5]/1
```
As you can see a list and a pointer will always be displayed. If you move the pointer the representation
will look different, but internally the *original list* will be the same.
```elixir
iex> a = CList.new([1, 2, 3, 4, 5])
#CList[1, 2, 3, 4, 5]/1
iex> b = CList.forward(a)
#CList[2, 3, 4, 5, 1]/2
iex> CList.equals?(a, b)
true
```
You can see that the list and the pointer of `a` and `b` differs, but the `CList`s are equals
because their sequential lists are the same.
And talking about the concept of `equal` on `CList`s, it is important to note that 2 `CList`s are
considered equal if they have the same size and their traversal sequence is exactly the same.
```elixir
iex> a = CList.new [1, 2, 3, 4, 5, 6]
#CList[1, 2, 3, 4, 5, 6]/1
iex> b = CList.new [5, 6, 1, 2, 3, 4]
#CList[5, 6, 1, 2, 3, 4]/1
iex> CList.equals?(a, b)
true
iex> b = CList.new [6, 5, 1, 2, 3, 4]
#CList[6, 5, 1, 2, 3, 4]/1
iex> CList.equals?(a, b)
false
```
## Original and current list
What `CList` stores at all times is what we call the *current list* (i.e., the rotated list) but
implicitly also store what we will call the *original list*, which is the *current list* when the
pointer is equal to 1.
```elixir
iex> a = CList.new([:a, :b, :c, :d, :e])
#CList[:a, :b, :c, :d, :e]/1
## Original list: [:a, :b, :c, :d, :e]
## Current list: [:a, :b, :c, :d, :e]
iex> CList.forward(a, 3)
#CList[:d, :e, :a, :b, :c]/4
## Original list: [:a, :b, :c, :d, :e]
## Current list: [:d, :e, :a, :b, :c]
```
## The pointer
Now is time to explain what the pointer value means. When the pointer is, for example, 2, it
means that the first value in the *current list* is equivalent to the value with index 2 in the
*original list* (remember, indexes in `CList` work on a base 1).
```elixir
## When pointer is 1, you see the original list
#CList[1, 2, 3, 4, 5]/1
^
|
+----------------------------------------------+
|
## When pointer is not 1, you see the list rotatated |
#CList[2, 3, 4, 5, 1]/2 |
| |
+----------------------------------+
```
## Enumerable
`CList` implements `Enumerable`, so you can play with `Streams` or use `Enum.*` functions.
```elixir
iex> a = CList.new([1, 2, 3, 4, 5])
#CList[1, 2, 3, 4, 5]/1
iex> Enum.take(a, 20)
[1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5]
iex> a
|> Stream.map(fn v -> v * 3 end)
|> Stream.map(fn v -> v - 1 end)
|> Enum.take(22)
[2, 5, 8, 11, 14, 2, 5, 8, 11, 14, 2, 5, 8, 11, 14, 2, 5, 8, 11, 14, 2, 5]
```
Since a `CList` could be iterated ad infinitum, the `Enum.*` functions that has not stop condition
will take the *current list* of the `CList` as enumerable input.
```elixir
iex> a = CList.new([1, 2, 3, 4, 5])
#CList[1, 2, 3, 4, 5]/1
iex> Enum.map(a, fn v -> v * 2 end)
[2, 4, 6, 8, 10]
iex> rl = CList.forward(a, 3)
#CList[4, 5, 1, 2, 3]/4
iex> Enum.map(a, fn v -> v * 2 end)
[8, 10, 2, 4, 6]
```
## TODO
One million tests `¯\_(ツ)_/¯`
## How to use
```elixir
defmodule TestCList do
use CList
def hello do
["h", "e", "l", "l", "o", " ", "w", "o", "r", "l", "d", "! "]
|> CList.new()
|> say_hello_but_in_a_cool_way()
end
def say_hello_but_in_a_cool_way(cl, count \\ 5)
def say_hello_but_in_a_cool_way(_, 0), do: IO.write("\n")
def say_hello_but_in_a_cool_way(CList.match([c | l]), count) do
IO.write(c)
:timer.sleep(200)
say_hello_but_in_a_cool_way(CList.forward(l), count - (c == "! " && 1 || 0))
end
end
```
You may also want to import `match/1` and `forward/1` to avoid having to explicitly specify
`CList`...
```elixir
defmodule TestCList do
use CList
import CList, only: [match: 1, forward: 1]
...
def say_hello_but_in_a_cool_way( match([c | l]), count) do
IO.write(c)
:timer.sleep(200)
say_hello_but_in_a_cool_way( forward(l), count - (c == "! " && 1 || 0))
end
...
end
```
## Installation
If [available in Hex](https://hex.pm/docs/publish), the package can be installed
by adding `clist` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:clist, "~> 0.1.0"}
]
end
```
Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
be found at <https://hexdocs.pm/clist>.