#include <functional>
#include <utility>

template<template<class ...> class M>
struct Monad {
    // return :: a -> m a
    template<typename T>
    static auto ret(T a) -> M<T>;
 
    // bind :: m a -> (a -> m b) -> m b
    template<typename T, typename U>
    static auto bind(M<T>, std::function<M<U>(T)>) -> M<U>;
};
 
// return :: a -> m a
template<template<class...> class M, typename T>
auto ret(T a) -> M<T>
{
    return Monad<M>::ret(std::move(a));
}
 
// (>>=) :: m a -> (a -> m b) -> m b
template<template<class...> class M, typename T, typename F>
auto operator >>= (M<T> ma, F fun) -> decltype(fun(std::declval<T>()))  // запутанно, но не знаю, как сделать лучше, чтобы работали лямбды
{
    using R = decltype(fun(std::declval<T>()));
    return Monad<M>::bind(ma, std::function<R(T)>(std::move(fun)));
}
 
// (>>) :: m a -> m b -> m b
template<template<class...> class M, typename T, typename U>
auto operator >> (M<T> ma, M<U> mb) -> M<U>
{
    return ma >>= [=](T){ return mb; };
}


template<typename T>
struct value { // просто коробка со значением
    value(T a)
        : x(a)
    {}
 
    T x;
};

// специализируем ret
template<>
template<typename T>
auto Monad<value>::ret(T a) -> value<T>
{
	return value<T>(a);
}

// специализируем bind
template<>
template<typename T, typename U>
auto Monad<value>::bind(value<T> d, std::function<value<U>(T)> f) -> value<U>
{
    return f(d.x);
}

#include <iostream>

auto succ(int x) -> value<int>
{
    return ret<value>(x + 1);
}
 
int main()
{
    auto v = (ret<value>(10) >>= succ) >>= succ;
 
    std::cout << v.x << std::endl;
}
