# Monad behaviour

Behaviour that provides monadic do-notation and pipe-notation.

## Terminology

The term “monad” is used here fairly loosely to refer to the whole concept of monads. One way of looking at monads is as a kind of “programmable semicolon”. Monads define what happens between the evaluation of the expressions. They control how and whether the results from one expression are passed to the next. For a better explanation of what monads are, look elsewhere, the internet is full of good (and not so good) monad tutorials; e.g. have a look at the HaskellWiki or read ”Real World Haskell” or ”Learn You a Haskell for Great Good!”.

## Usage

To use do-notation you need a module that implements Monad’s callbacks,
i.e. the module needs to have `return/1`

and `bind/2`

. This allows you to
write stuff like:

```
def call_if_safe_div(f, x, y) do
require Monad.Maybe, as: Maybe
import Maybe
Maybe.m do
result <- case y == 0 do
true -> fail "division by zero"
false -> return x / y
end
return f.(result)
end
end
```

The example above uses the `Maybe`

monad to define `call_if_safe_div/3`

. This
function takes three arguments: a function `f`

and two numbers `x`

and `y`

. If
`x`

is divisible by `y`

, then `f`

is called with `x / y`

and the return value
is `{:just, f.(x / y)}`

, else the computation fails and the return value is
`:nothing`

.

## Do-Notation

The do-notation supported is pretty simple. Basically there are three rules to remember:

Every “statement” (i.e. thing on it’s own line or separated by

`;`

) has to return a monadic value unless it’s a “let statement”.To use the value “inside” a monad write “pattern <- action” where “pattern” is a normal Elixir pattern and “action” is some expression which returns a monadic value.

- To use ordinary Elixir code inside a do-notation block prefix it with
`let`

. For multiple expressions or those for which precedence rules cause annoyances you can use`let`

with a do block.

## Defining Monads

To define your own monad create a module and use `use Monad`

. This marks the
module as a monad behaviour. You’ll need to define `return/1`

and `bind/2`

.

Here’s an example which defines the `List`

monad:

```
defmodule Monad.List do
use Monad
def return(x), do: [x]
def bind(x, f), do: Enum.flat_map(x, f)
end
```

### Monad Laws

`return/1`

and `bind/2`

need to obey a few rules (the so-called “monad laws”)
to avoid surprising the user. In the following equivalences `M`

stands for
your monad module, `a`

for an arbitrary value, `m`

for a monadic value and `f`

and `g`

for functions that given a value return a new monadic value.

Equivalence means you can always substitute the left side for the right side and vice versa in an expression without changing the result or side-effects

- “left identity”:
`M.bind(M.return(m), f) <=> f.(m)`

- “right identity”:
`M.bind(m, &M.return/1) <=> m`

- “associativity”:
`M.bind(m, f) |> M.bind(g) <=> m |> M.bind(fn y -> M.bind(f.(y), g))`

See the HaskellWiki for more explanation.

## Pipe Support

For monads that implement the `Monad.Pipeline`

behaviour the `p`

macro
supports monadic pipelines. For example:

```
Error.p, (File.read("/tmp/foo")
|> Code.string_to_quoted(file: "/tmp/foo")
|> Macro.safe_term)
```

If any of the terms returns `{:error, x}`

then that’s the return value of the
pipeline, when a term returns `{:ok, x}`

the value `x`

is passed to the next.

You can also use a `do`

-block for less clutter:

```
Error.p do
File.read("/tmp/foo")
|> Code.string_to_quoted(file: "/tmp/foo")
|> Macro.safe_term
end
```

Under the hood pipe binding works by calling the `pipebind`

function in a
monad module. If you use `use Monad.Pipeline`

one is automatically created
(you can still override it though).

The `pipebind`

function receives the AST form of a value argument and a
function. It has to return some AST that essentially does what bind does but
with a function that’s missing the first argument. See the example below.

# Summary

## Macros

Helper for defining monads

## Callbacks

Bind a value in the monad to the passed function which returns a new monad

Inject a value into a monad

# Types

`monad :: any`

# Macros

# Callbacks

Bind a value in the monad to the passed function which returns a new monad.