Skip to content

Instantly share code, notes, and snippets.

@laparca
Created August 30, 2019 11:50
Show Gist options
  • Save laparca/35c7065e0f9d4256a611ec5d6568e3c2 to your computer and use it in GitHub Desktop.
Save laparca/35c7065e0f9d4256a611ec5d6568e3c2 to your computer and use it in GitHub Desktop.
Simple monad concept in C++
#include <functional>
namespace lzcoders {
namespace MonadHelpers {
template<typename T> struct value_type { using type = typename std::decay<T>::type::value_type; };
template<typename T> using ValueType = typename value_type<T>::type;
struct dummy {
dummy(const dummy&) = default;
dummy(dummy&&) = default;
dummy() = default;
};
template<class T, class X> struct rebind;
template<class T, class X> using rebind_t = typename rebind<T, X>::type;
template<template<class...> class T, class X, class Y, class... Z> struct rebind<T<X, Z...>, Y> {
using type = T<Y, Z...>;
};
template<typename M> using dummy_function = std::function<rebind_t<M, dummy>(ValueType<M> const&)>;
template<typename... Monad>
struct monad_t;
}
template<typename M>
concept bool Monad = requires (M m) {
typename MonadHelpers::ValueType<M>;
typename MonadHelpers::monad_t<M>;
{ MonadHelpers::monad_t<M>::wrap(MonadHelpers::ValueType<M>{}) } -> M;
{ MonadHelpers::monad_t<M>::apply(m, MonadHelpers::dummy_function<M>{}) } -> MonadHelpers::rebind_t<M, MonadHelpers::dummy>;
};
template<template<typename...>typename M, typename T, typename... Ts> requires Monad<M<T, Ts...>>
auto mwrap(T&& t) {
return MonadHelpers::monad_t<M<T, Ts...>>::wrap(std::forward<T>(t));
}
template<typename M, typename F> requires Monad<M>
auto mapply(M&& m, F&& f) {
return MonadHelpers::monad_t<M>::apply(std::forward<M>(m), std::forward<F>(f));
}
template<typename M, typename F> requires Monad<M>
auto operator>>(M&& m, F&& f) {
return mapply(std::forward<M>(m), std::forward<F>(f));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment