libreglisse
is a library of monadic types implemented using C++20. It currently contains the maybe
, either
and result
monads.
The library also provides a set of extensible operations that can be applied on the monadic types through the pipe
operator (operator|
).
- A C++20 capable compiler
- build2 for build & packaging system
The library provides three monadic types: maybe
, result
and either
. They are quite small in size and provide a
bare API for storing & accessing the data store within the monadic types.
maybe
is a monadic type that either holds a value or is empty. It provides functions to query the state of the monad
with is_some()
and is_none()
.
The monad can be constructed empty using the none
value, or using the some
class as follows:
maybe<int> m_empty = none;
maybe<int> m_full = some(1);
You can borrow the value stored within the monad when it is an lvalue with the function borrow()
You can take the value stored within the monad when it is an rvalue with the function take()
or take_or()
If you attemp to borrow or take the value stored when the monad is empty, an abort()
will be called.
result
is a monadic type that hold either a value or an error. It provides functions to query the state of the monad
with is_ok()
and is_err()
.
The monad can be constructed using the ok
and err
classes as follows:
result<int, std::string> m_ok = ok(1);
result<int, std::string> m_err = err("hello");
You can borrow the value stored within the monad when it is an lvalue with the function borrow()
and the error using
borrow_err()
You can take the value stored within the monad when it is an rvalue with the function take()
and the error using
take_err()`
If you attemp to borrow or take the value stored when the monad holds an error, an abort()
will be called. The
inverse is also true
either
is a monadic type that, as the name implies, holds one type or another. You can check which side the either
currently hold with is_left()
and is_right()
. either
is essentially a more generic version of result
.
The monad can be constructed using the left
and right
classes as follows:
either<int, std::string> m_left = left(1);
either<int, std::string> m_right = right("hello");
You can borrow the right value stored within the monad when it is an lvalue with the function borrow_right()
and the
left value using borrow_left()
You can take the right value stored within the monad when it is an rvalue with the function take_right()
and the left
value using take_left()
If you attemp to borrow or take the value stored on the right when the monad holds a left, an abort()
will be called. The
inverse is also true
Operations is the name given to function that can be aplied on a monadic type to transform, alter or chain sequences of
operations. The operator|
API is used to resemble unix piping. The API was also built in a way to allow for easy
extensions, as shown in the next section.
The library comes with a set of premade operations and they are:
maybe
:transform
: Transform the value stored within the monad, if it exists.and_then
: Chain a function returning a maybe using the value stored, if it exist.or_else
: Chain a function returning a maybe if no value is stored.
result
:transform
: Transform the value stored within the monad, if it exists.transform_err
: Transform the error stored within the monad, if it exists.and_then
: Chain a function returning a result using the value stored, if it exist.or_else
: Chain a function returning a result using the error stored, if it exist.
either
:transform_left
: Transform the right value stored within the monad, if it exists.transform_right
: Transform the left value stored within the monad, if it exists.transform_join_left
: Chain a function returning a either using the left value stored, if it exist.transform_join_right
: Chain a function returning a either using the right value stored, if it exist.
You can extend the piping API on the monadic types by implement a functor class and create an instance of the
operation
class template like so:
struct sample_op_fn
{
template <typename Func>
constexpr auto operator()(const maybe<int>&, Func some_func);
}
const constexpr operation<sample_op_fn> sample_op = {};