[![Hex pm](](
[![Inline docs](](

# Exordia

**Yeah yet another module with convenience macros/functions for piping.**

But this one is the best one.

## Installation

The package can be installed by adding `exordia` to your list of dependencies in

def deps do
    {:exordia, "~> 0.8"}

## Background

The normal pipe operator is rather limited if you want to do anything other than
crash on any failure. It can also be annoying how even if you want to crash on
failure, some functions only provide an {:ok, result} or {:error, reason} return
that you're obligated to handle.

The with language construct is interesting but unless everything in the with
block returns a distinguishable error message, it can be difficult to determine
where in the block a failure occurred.

## Concept

So instead of that shit, we strip the :ok's off of everything and turn :error,
{:error, x} and {:error, x, y} into an Error struct so everything piped through
is either a raw value or an Error struct.

The ~> operator pipes the value to the function unless it is an error, in which
case the function isn't called at all and the error falls through. So if you
only use the ~> operator, any error will drop through as the return value of
the chain.

The <~ operator is the opposite -- it only pipes unhandled errors -- non-errors
and handled errors fall through. (The Error struct has a :handled field which
marks an error as handled and prevents further error handlers from picking it

This allows for a very elegant pattern.

Also we support _ as a placeholder if you want to pipe to an argument other than
the first and some other cool stuff.

use Exordia

~> authenticate()
<~ handle_auth_errors()
~> validate_input()
<~ handle_validation_errors()
~> process_input()
<~ handle_processing_errors()
~> show_success_message()
<~ handle_success_errors()

## Caveat

We provide functions to convert an Error to a tuple or a value to an :ok tuple
for when this is needed, but if you're pulling some value that might randomly be
an :ok or :error tuple, just use |> for that portion of your code and use better
programming practices in the future.

## So why not use an existing solution or monads or something?

I haven't seen any other solutions that allow for this level of elegance.

Haskell-style monads are cool and all but the attempts I've seen to shoehorn
them into Elixir don't seem useful. I think more language-level support would be
needed for this to be of any real value.