This is Monad, a C++ module that provides monadic interface for C++.
Monad is a concept in functional programming. It is a design pattern that allows structuring programs generically while automating away boilerplate code needed by the program logic. ==Monads achieve this by providing their own data type, which represents a specific form of computation, along with one procedure to wrap values of any basic type within the monad (yielding a monadic value) and another to compose functions that output monadic values (called monadic functions).
from Wikipedia
Monad can forward its internal state to the next function flawlessly. It is very useful in functional programming. Because they are pure functions so are capable of stateless, pure functions, no side effects.
In C++, Method Chaining simulates the pure functional programming, Hiding its value and state, and only providings the interface to access the Perfect value. noexcept stimulates no side effects. Unfortunately there is no dictionary meaning pure function with no side effect in C++ (unless they are metafunctions).
Just a header file. Copy it to your project.
C++20or later- Modules & Concepts Support
- constexpr Destructor
-
Monadhas[[nodiscard]]attribute. -
The underlying type
Tshould be copyable;
import Utility.Monad;Imports util::Monad.
// Default initializer
util::Monad<T> monad{};
// Constexpr initializer
constexpr util::Monad<T> cmonad{};// Copy constructors
util::Monad<T> pmonad1{ monad };
constexpr util::Monad<T> pmonad2{ cmonad };
// Move constructors
util::Monad<T> mmonad1{ std::move(monad) };
constexpr util::Monad<T> mmonad2{ std::move(cmonad) };if_then(invocable<Type, Args...>, Args...) -> self 1
Monad& if_then(functor, [args...]) noexcept(?)Executes the functor if this Monad has a value, and returns the Monad itself.
and_then(invocable<Type, Args...>, Args...) -> Monad 1
Monad<U> and_then<U>(functor: Monad<U>, [args...]) noexcept(?)If this Monad has a value, executes functor and returns it, or returns empty Monad<U>.
functor should have to return a specialization of Monad (aka. Monad<U>).
R and_then<R>(safe: R, fail: R) noexcept(?)If this Monad has a value, executes safe and returns it, or executes fail and returns it.
Both invocables should have to return the same type.
forward<U>(invocable<Type>, U&& default_value) -> U 1
U forward<U>(functor: U, default_value: U) noexcept(?)If this Monad has a value, executes functor and returns it, or returns empty default_value.
else_than(invocable<Type, Args...>, Args...) -> self 1
Monad& else_than<U>(functor, [args...]) noexcept(?)Executes the functor if this Monad has ==no value==, and returns the Monad itself.
or_else(invocable<Type, Args...>, Args...) -> Monad 1
Monad<U> or_else<U>(functor: Monad<U>, [args...]) noexcept(?)If this Monad has ==no value==, executes functor and returns it, or returns empty Monad<U>.
functor should have to return a specialization of Monad (aka. Monad<U>).
bool has_value() const noexceptvalue() & -> T& 3
T& value() & noexceptvalue() const& -> const T& 3
const T& value() const& noexceptvalue() && -> T&& 3
T&& value() && noexceptvalue() const&& -> const T&& 3
const T&& value() const&& noexceptT value_or(const T&) const& noexceptT value_or(T&&) const& noexceptT value_or(const T&) && noexceptT&& value_or(T&&) && noexceptT get() const& noexceptT&& get() && noexceptexplicit operator T() const noexceptexplicit operator bool() const noexceptimport Utility.Monad;
// They always have a state.
Monad<int> Send(::SOCKET handle, const char* buffer, const int& size)
{
return ::send(handle, buffer, size, 0);
}
// They always have a state.
Monad<int> Recv(::SOCKET handle, char* buffer, const int& size)
{
return ::recv(handle, buffer, size, 0);
}
bool echo_once()
{
::SOCKET my_socket;
char my_recv_buffer[1024]{};
int my_recv_size{};
constexpr int FirstRecvSize = 1024;
return Recv(my_socket, my_recv_buffer, FirstRecvSize).and_then(
[&](int&& received_size) noexcept -> Monad<int>
{
if (0 < received_size)
{
return recv_size += received_size;
}
else
{
return util::nullopt;
}
}
).and_then([](int&& buffer_bytes) -> Monad<bool> {
// packets
// ...
return true;
}).value_or(false);
}template <std::copyable T>
class [[nodiscard]] Monad
{
public:
template<typename Fn, typename... Args>
using monad_result_t = std::remove_cvref_t<std::invoke_result_t<Fn, Args...>>;
constexpr Monad() noexcept = default;
constexpr ~Monad() noexcept = default;
constexpr Monad(std::nullopt) noexcept;
template<typename U>
constexpr Monad(std::reference_wrapper<U>) noexcept = default;
template<typename Fn, typename... Args>
requires std::invocable<Fn, T&, Args...>
constexpr Monad&
if_then(Fn&& action, Args&&... args) &;
template<typename Fn, typename... Args>
requires std::invocable<Fn, const T&, Args...>
constexpr const Monad&
if_then(Fn&& action, Args&&... args) const&;
template<typename Fn, typename... Args>
requires std::invocable<Fn, T&&, Args...>
constexpr Monad&&
if_then(Fn&& action, Args&&... args) &&;
template<typename Fn, typename... Args>
requires std::invocable<Fn, const T&&, Args...>
constexpr const Monad&&
if_then(Fn&& action, Args&&... args) const&&;
template<typename Fn, typename... Args>
requires std::invocable<Fn, T&, Args...>
constexpr auto
and_then(Fn&& action, Args&&... args) &;
template<typename Fn, typename... Args>
requires std::invocable<Fn, const T&, Args...>
constexpr auto
and_then(Fn&& action, Args&&... args) const&;
template<typename Fn, typename... Args>
requires std::invocable<Fn, T&&, Args...>
constexpr auto
and_then(Fn&& action, Args&&... args) &&;
template<typename Fn, typename... Args>
requires std::invocable<Fn, const T&&, Args...>
constexpr auto
and_then(Fn&& action, Args&&... args) const&&;
template<std::invocable<T&> Lfn, std::invocable<T&> Rfn>
constexpr
monad_result_t<Lfn, const T&>
transform(Lfn&& safe_action, Rfn&& fail_action) &;
template<std::invocable<T&> Lfn, std::invocable<T&> Rfn>
constexpr
monad_result_t<Lfn, const T&>
transform(Lfn&& safe_action, Rfn&& fail_action) const&;
template<std::invocable<T&&> Lfn, std::invocable<T&&> Rfn>
constexpr
monad_result_t<Lfn, const T&&>
transform(Lfn&& safe_action, Rfn&& fail_action) &&;
template<std::invocable<const T&&> Lfn, std::invocable<const T&&> Rfn>
constexpr
monad_result_t<Lfn, const T&&>
transform(Lfn&& safe_action, Rfn&& fail_action) const&&;
template<std::invocable<T&> Fn, typename Uty>
constexpr
Uty&&
forward(Fn&& safe_action, Uty&& default_value) &;
template<std::invocable<T&> Fn, typename Uty>
constexpr
Uty&&
forward(Fn&& safe_action, Uty&& default_value) const&;
template<std::invocable<T&> Fn, typename Uty>
constexpr
Uty&&
forward(Fn&& safe_action, Uty&& default_value) &&;
template<std::invocable<T&> Fn, typename Uty>
constexpr
Uty&&
forward(Fn&& safe_action, Uty&& default_value) const&&;
template<typename Fn, typename... Args>
requires std::invocable<Fn, T&, Args...>
constexpr
Monad&
else_than(Fn&& action, Args&&... args) &;
template<typename Fn, typename... Args>
requires std::invocable<Fn, const T&, Args...>
constexpr
const Monad&
else_than(Fn&& action, Args&&... args) const&;
template<typename Fn, typename... Args>
requires std::invocable<Fn, T&&, Args...>
constexpr
Monad&&
else_than(Fn&& action, Args&&... args) &&;
template<typename Fn, typename... Args>
requires std::invocable<Fn, const T&&, Args...>
constexpr
const Monad&&
else_than(Fn&& action, Args&&... args) &&;
template<typename Fn, typename... Args>
requires std::invocable<Fn, T&, Args...>
constexpr
auto
or_else(Fn&& action, Args&&... args) &;
template<typename Fn, typename... Args>
requires std::invocable<Fn, const T&, Args...>
constexpr
auto
or_else(Fn&& action, Args&&... args) const&;
template<typename Fn, typename... Args>
requires std::invocable<Fn, T&&, Args...>
constexpr
auto
or_else(Fn&& action, Args&&... args) &&;
template<typename Fn, typename... Args>
requires std::invocable<Fn, const T&&, Args...>
constexpr
auto
or_else(Fn&& action, Args&&... args) &&;
constexpr T& value() &;
constexpr const T& value() const&;
constexpr T& value() &&;
constexpr const T& value() const&&;
constexpr T get() const&;
constexpr T&& get() &&;
constexpr T value_or(const T& default_value) const&;
constexpr T value_or(T&& default_value) const&;
constexpr T value_or(const T& default_value) &&;
constexpr T&& value_or(T&& default_value) &&;
constexpr bool has_value() const;
explicit constexpr operator T() const;
explicit constexpr operator bool() const;
private:
T _Value;
bool _Has_value;
};- Contributions are always welcome!