# Wonderland
<img src="priv/img/logo.png" alt="logo"/>
Tons of boring `case`, `if` or `with` low level expressions and boilerplate pattern matching clauses with guards is not functional programming. Real functional programming is **fun**. It operates with highly reusable polymorphic abstractions and compositions of them. Welcome to the Wonderland, Elixir functional programming foundation!
## Quick Start
```elixir
defmodule Demo do
use Wonderland
@spec parse(term) :: Either.t(String.t(), Date.t())
def parse(x) when is_binary(x) do
x
|> Date.from_iso8601()
|> lift(Either)
|> ex_first(&"#{x} is #{&1}")
end
def parse(x) do
Either.left("invalid date #{inspect(x)}")
end
@spec between?(
Date.t(),
Date.t(),
Date.t()
) :: boolean()
def between?(x, y, z) do
Date.range(x, z)
|> Enum.member?(y)
end
end
```
And then let's have some fun with Applicatives:
```elixir
iex(2)> use Wonderland
:ok
iex(3)> import Demo
Demo
iex(4)> x = parse("1999-01-23")
#Function<3.132474729/2 in Wonderland.Data.Either.eval/2>
iex(5)> y = parse("2000-01-23")
#Function<3.132474729/2 in Wonderland.Data.Either.eval/2>
iex(6)> z = parse("2020-01-23")
#Function<3.132474729/2 in Wonderland.Data.Either.eval/2>
iex(7)> bad = parse("1999-99-99")
#Function<3.132474729/2 in Wonderland.Data.Either.eval/2>
iex(8)> (&between?/3) <~ x <<~ bad <<~ z |> unlift
{:error, "1999-99-99 is invalid_date"}
iex(9)> (&between?/3) <~ x <<~ y <<~ z |> unlift
{:ok, true}
iex(10)> (&between?/3) <~ x <<~ z <<~ y |> unlift
{:ok, false}
```
## Boundary
Wonders (Wonderland abstractions) are well encapsulated, and they can not be corrupted by boring reality. Interaction with regular Elixir is always explicit: `lift/2` lifts Elixir expression into Wonderland, and `unlift/1` is acting opposite:
```elixir
@spec lift(term, type) :: wonder
@spec unlift(wonder) :: term
```
## Translation Table
| Type Class | Function | Haskell | Elixir |
|-------------|-----------|---------|----------|
| Functor | fmap | <$> | <~ |
| Functor | flip fmap | <&> | ~> |
| Monad | bind | >>= | >>> |
| Applicative | ap | <*> | <<~ |
## Installation
The package can be installed by adding `wonderland` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:wonderland, "~> 0.1"}
]
end
```