Examples
transformations
Maybe
transform
We can transform the value stored in a maybe by piping the transform
operation as follows. It transforms the value
using a function or lambda to modify, alter or change the value & type store in the monad.
using namespace reglisse;
maybe<int> m_int = some(1);
maybe<std::string> m_str = m_int | transform([](int i){ return std::to_string(i); });
You can see that the monad m_str hold a value of type string, which is the return type of the lambda passed in
transform
Do note that if the maybe
is empty, the transform
will not do anything to the value.
Result
transform
transform
also work on result
monads in the same way.
using namespace reglisse;
result<int, float> r_int = ok(1);
result<std::string, float> = r_str = r_int | transform([](int i){ return std::to_string(i); });
You can see that the syntax & behaviour is the same as shown above for the maybe monad.
Do note that if the result
contains an error, the transform
will not do anything to the value.
transform_err
transform_err
does the same thing as transform
but on the error side of the result.
using namespace reglisse;
result<int, float> r_int = ok(1);
result<int, std::string> = r_str = r_int
| transform_err([](int i) -> std::string { return i == 0 ? "hello" : "world"; });
Do note that if the result
contains a value, the transform_err
will not do anything to the error.
Either
transform_left
transform_left
applies a function to the value stored on the left hand side of the monad.
using namespace reglisse;
either<int, float> e_float = left(1.0f);
either<std::string, float> e_str = e_float
| transform_left([](int i) { return std::format("{}", i); };
Do note that if the either
monad doesn't contain a value on the left, the function passed through transform_left
will not be invoked, but the monad's left hand type will be modified.
transform_right
transform_right
applies a function to the value stored on the right hand side of the monad.
using namespace reglisse;
either<int, float> e_float = left(1.0f);
either<int, std::string> e_str = e_float
| transform_right([](float f) { return std::format("{}", f); };
Do note that if the either
monad doesn't contain a value on the right, the function passed through transform_right
will not be invoked, but the monad's right hand type will be modified.
Join transformations
Maybe
and_then
The and_then
operation is a transform join operation. It calls a function that returns another maybe
monadic type,
and joins it with the original maybe
.
using namespace reglisse;
maybe<int> m_int = some(1);
maybe<std::string> m_str = m_int
| and_then([](int i) -> maybe<std::string> { return i % 2 ? std::to_string(i) : none; })
If the maybe
is empty, the function will not be invoked.
or_else
The or_else
operation works the same as and_then
but it is only applied when the monad is empty.
using namespace reglisse;
maybe<int> m_int = some(1);
maybe<std::string> m_str = m_int
| or_else([] { return maybe(some(1)); })
If the maybe
is empty, the function will not be invoked.
Result
and_then
The and_then
operation calls a function that returns another result
monadic type,
and joins it with the original result
.
using namespace reglisse;
enum struct err_code { e_err_1, e_unknown };
result<int, err_code> r_int = ok(1);
result<std::string, err_code> r_str = r_int
| and_then([](int e) -> result<int, std::string> {
return e != 0 ? ok(to_string(e)) : err(err_code::e_err_1);
});
If the either
contains an error, the function will not be invoked.
or_else
The or_else
operation works the same as and_then
but it is only applied when the monad is holds an error.
using namespace reglisse;
enum struct err_code { e_err_1, e_unknown };
result<int, err_code> r_int = ok(1);
result<int, std::string> r_str = r_int
| or_else([](err_code e) -> result<int, std::string> {
return e != err_code::e_unknown ? ok(1) : err("e_err_1");
});
If the either
contains a value, the function will not be invoked.
Either
transform_join_left
transform_join_left
takes for input a function who's input is the left hand type of the either
monad. That function
must also return an either
which will be joined with the current monad with left hand type being determined by the
transformation and the right hand type being the same as the original monad.
using namespace reglisse;
either<int, std::string> e_int = left(1);
either<float, std::string> e_res = e_int
| transform_join_left([](int i) -> either<float, std::string> {
return left(static_cast<float>(i));
});
Do note that if the original monad (e_int) in the example contained a value in it's right, the transform_join_left
operation
actually call the input function, but it will modify the either
's left type.
transform_join_right
transform_join_right
takes for input a function who's input is the right hand type of the either
monad. That
function must also return an either
which will be joined with the current monad with the right hand type determined by
the transformation and the left hand type being the same as the original monad.
using namespace reglisse;
either<int, std::string> e_str = right("hello");
either<float, std::string> e_res = e_str
| transform_join_left([](std::string& i) -> either<int, std::string_view> {
return right(std::string_view(i));
});
Do note that if the original monad (e_str) in the example contained a value in it's lfet, the transform_join_right
operation
actually call the input function, but it will modify the either
's right type.
Wrapping Exceptions
libreglisse
provides a helper function for functions that return a type and throw an exception at the same time called
try_wrap
.
auto my_func(bool b) -> int
{
if (b)
{
throw std::exception();
}
else
{
return 0;
}
}
result<int, std::exception> res = try_wrap<std::exception>(my_func, true);