Type systemC ++ is not powerful enough to disengage from higher-grade types, but since the patterns are ducky, you can ignore this and simply execute the various Monads separately and then express the monadic operations as SFINAE patterns. Ugly, but best.
This comment kills money. Again and again, I see people trying to make "covariant" and / or abuse inheritance. For better or for worse, conceptual generalized programming, in my opinion, is more reasonable. Here is a quick demo that will use the power of C ++ 11 for brevity and clarity, although the same functionality should be implemented in C ++ 03:
(*: for a competing opinion, refer to "Ugly, but the best it gets" in my quote!)
#include <utility> #include <type_traits> // SFINAE utility template<typename...> struct void_ { using type = void; }; template<typename... T> using Void = typename void_<T...>::type; /* * In an ideal world std::result_of would just work instead of all that. * Consider this as a write-once (until std::result_of is fixed), use-many * situation. */ template<typename Sig, typename Sfinae = void> struct result_of {}; template<typename F, typename... Args> struct result_of< F(Args...) , Void<decltype(std::declval<F>()(std::declval<Args>()...))> > { using type = decltype(std::declval<F>()(std::declval<Args>()...)); }; template<typename Sig> using ResultOf = typename result_of<Sig>::type; /* * Note how both template parameters have kind *, MonadicValue would be * ma, not m. We don't whether MonadicValue is a specialization of some M<T> * or not (or derived from a specialization of some M<T>). Note that it is * possible to retrieve the a in ma via typename MonadicValue::value_type * if MonadicValue is indeed a model of the proper concept. * * Defer actual implementation to the operator() of MonadicValue, * which will do the monad-specific operation */ template< typename MonadicValue , typename F /* It is possible to put a self-documenting assertion here that will *not* SFINAE out but truly result in a hard error unless some conditions are not satisfied -- I leave this out for brevity , Requires< MonadicValueConcept<MonadicValue> // The two following constraints ensure that // F has signature a -> mb , Callable<F, ValueType<MonadicValue>> , MonadicValueConcept<ResultOf<F(ValueType<MonadicValue>)>> >... */ > ResultOf<MonadicValue(F)> bind(MonadicValue&& value, F&& f) { return std::forward<MonadicValue>(value)(std::forward<F>(f)); } // Picking Maybe as an example monad because it easy template<typename T> struct just_type { using value_type = T; // Encapsulation omitted for brevity value_type value; template<typename F> // The use of ResultOf means that we have a soft contraint // here, but the commented Requires clause in bind happens // before we would end up here ResultOf<F(value_type)> operator()(F&& f) { return std::forward<F>(f)(value); } }; template<typename T> just_type<T> just(T&& t) { return { std::forward<T>(t) }; } template<typename T> just_type<typename std::decay<T>::type> make_just(T&& t) { return { std::forward<T>(t) }; } struct nothing_type { // Note that because nothing_type and just_type<T> // are part of the same concept we *must* put in // a value_type member type -- whether you need // a value member or not however is a design // consideration with trade-offs struct universal { template<typename T> operator T(); }; using value_type = universal; template<typename F> nothing_type operator()(F const&) const { return {}; } }; constexpr nothing_type nothing;
Then you can write something like bind(bind(make_just(6), [](int i) { return i - 2; }), [](int i) { return just("Hello, World!"[i]); }) . Keep in mind that the code in this message is incomplete in that the wrapped values ββare not sent properly, there should be errors as soon as the const -qualified and move-only types are involved. You can see the code in action (with GCC 4.7) here , although this may be incorrect, since everything that it does is not a statement of the trigger. ( The same code for ideone for future readers.)
The core of the solution is that none of just_type<T> , nothing_type or MonadicValue (inside bind ) is a monad, but a type for some monadic values ββof the main monad - just_type<int> and nothing_type together is a monad (like - I Now I put aside the question of good, but I remember that it is possible, for example, to repeat the markup of templates after the fact, as for std::allocator<T> !). Since such a bind should be somewhat lenient in what it accepts, but note that this does not mean that it should accept everything.
Of course, it is entirely possible to have a template of class M such that M<T> is a MonadicValue and bind(m, f) model MonadicValue has ever been of type M<U> , where M is of type M<T> . In a way, this will make M monad (with the form * -> * ), and the code will still work. (And speaking of Maybe , perhaps adapting boost::optional<T> to have a monadic interface would be a good exercise.)
An astute reader would notice that there is no equivalent to return , everything is done using the just and make_just , which are analogues of the just constructor. This is necessary for brevity. A possible solution would be to write pure , which performs the return task, and returns a value that is implicitly converted to any type that models MonadicValue (by deferring the instance for some MonadicValue::pure ).
There are constructive considerations, although the limited C ++ output type means that bind(pure(4), [](int) { return pure(5); }) will not work out of the box. However, this is not an insurmountable problem. (Some contours of the solution are bind overloads, but this is inconvenient if you add MonadicValue to our interface, since any new operation should also be able to explicitly process pure values ββor make a pure value a MonadicValue model.)