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);