[![Tests](https://github.com/moritzploss/do/actions/workflows/tests.yml/badge.svg)](https://github.com/moritzploss/do/actions/workflows/tests.yml)
## do
This package brings monads, applicatives, functors, and `do`-notation to
Erlang. It provides behaviours for relevant type classes, as well as
implementations for commonly used class instances.
## Quick Start
The `either` type is defined as a tuple of either `{ok, Value}` or
`{error, Reason}`, and is a member of the functor, applicative and monad type
class. The `?fmap` macro can be used to map functions over functors:
```erlang
-include_lib("do/include/do.hrl").
add1(N) -> N + 1.
fmap_example() ->
{ok, 2} = ?fmap(fun add1/1, {ok, 1}),
{error, rsn} = ?fmap(fun add1/1, {error, rsn}),
[2, 3, 4] = ?fmap(fun add1/1, [1, 2, 3]),
#{a => 2} = ?fmap(fun add1/1, #{a => 1}).
```
The `?do` macro consecutively executes functions inside the `either` monad.
The macro takes a start value, and a list of functions. The functions must
each take either 0 or 1 argument(s) and must return an `either` monad. On
execution, the start value is passed to the first function in the provided
list. If the function returns `{ok, Val}`, the second function is called with
`Val`, and so on:
```erlang
-include_lib("do/include/do.hrl").
maybe_add1(N) when N > 5 -> {error, greater_five};
maybe_add1(N) -> {ok, N + 1}.
do_example1() ->
{ok, 3} = ?do({ok, 0}, [ fun maybe_add1/1,
fun maybe_add1/1,
fun maybe_add1/1]).
```
If a function returns an error tuple `{error, Reason}`, the error is returned
immediately.
```erlang
do_example2() ->
{error, greater_five} = ?do({ok, 0}, [ fun maybe_add1/1,
fun maybe_add1/1,
fun maybe_add1/1,
fun maybe_add1/1,
fun maybe_add1/1,
fun maybe_add1/1]).
```