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 useletwith 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.