I am trying to implement the Maybe monad from Haskell using the lambda functions in C++11 and templates. Here\'s what I have so far
#include #i
Literally copy & pasting from Haskell style "Maybe" type & *chaining* in C++11
This is probably what you really want to achieve
#include #include #include #include #include typedef long long int int64; namespace monad { namespace maybe { struct Nothing {}; template < typename T > struct Maybe { template < typename U, typename Enable = void > struct ValueType { typedef U * const type; }; template < typename U > struct ValueType < U, typename std::enable_if < std::is_reference < U >::value >::type > { typedef typename std::remove_reference < T >::type * const type; }; typedef typename ValueType < T >::type value_type; value_type m_v; Maybe(Nothing const &) : m_v(0) {} struct Just { value_type m_v; Just() = delete; explicit Just(T &v) : m_v(&v) { } }; Maybe(Just const &just) : m_v(just.m_v) { } }; Nothing nothing() { return Nothing(); } template < typename T > Maybe < T > just(T &v) { return typename Maybe < T >::Just(v); } template < typename T > Maybe < T const > just(T const &v) { return typename Maybe < T const >::Just(v); } template < typename T, typename R, typename A > Maybe < R > operator | (Maybe < T > const &t, R (*f)(A const &)) { if (t.m_v) return just < R >(f(*t.m_v)); else return nothing(); } template < typename T, typename R, typename A > Maybe < R > operator | (Maybe < T > const &t, Maybe < R > (*f)(A const &)) { if (t.m_v) return f(*t.m_v); else return nothing(); } template < typename T, typename R, typename A > Maybe < R > operator | (Maybe < T > const &t, R (*f)(A &)) { if (t.m_v) return just < R >(f(*t.m_v)); else return nothing(); } template < typename T, typename R, typename A > Maybe < R > operator | (Maybe < T > const &t, Maybe < R > (*f)(A &)) { if (t.m_v) return f(*t.m_v); else return nothing(); } template < typename T, typename R, typename... A > Maybe < R > operator | (Maybe < T const > const &t, R (T::*f)(A const &...) const) { if (t.m_v) return just < R >(((*t.m_v).*f)()); else return nothing(); } template < typename T, typename R, typename... A > Maybe < R > operator | (Maybe < T const > const &t, Maybe < R > (T::*f)(A const &...) const) { if (t.m_v) return just < R >((t.m_v->*f)()); else return nothing(); } template < typename T, typename R, typename... A > Maybe < R > operator | (Maybe < T const > const &t, R (T::*f)(A const &...)) { if (t.m_v) return just < R >(((*t.m_v).*f)()); else return nothing(); } template < typename T, typename R, typename... A > Maybe < R > operator | (Maybe < T const > const &t, Maybe < R > (T::*f)(A const &...)) { if (t.m_v) return just < R >((t.m_v->*f)()); else return nothing(); } template < typename T, typename A > void operator | (Maybe < T > const &t, void (*f)(A const &)) { if (t.m_v) f(*t.m_v); } }} struct Account { std::string const m_id; enum Type { CHECKING, SAVINGS } m_type; int64 m_balance; int64 withdraw(int64 const amt) { if (m_balance < amt) m_balance -= amt; return m_balance; } std::string const &getId() const { return m_id; } }; std::ostream &operator << (std::ostream &os, Account const &acct) { os << "{" << acct.m_id << ", " << (acct.m_type == Account::CHECKING ? "Checking" : "Savings") << ", " << acct.m_balance << "}"; } struct Customer { std::string const m_id; std::deque < Account > const m_accounts; }; typedef std::map < std::string, Customer > Customers; using namespace monad::maybe; Maybe < Customer const > getCustomer(Customers const &customers, std::string const &id) { auto customer = customers.find(id); if (customer == customers.end()) return nothing(); else return just(customer->second); }; Maybe < Account const > getAccountByType(Customer const &customer, Account::Type const type) { auto const &accounts = customer.m_accounts; auto account = std::find_if(accounts.begin(), accounts.end(), [type](Account const &account) -> bool { return account.m_type == type; }); if (account == accounts.end()) return nothing(); else return just(*account); } Maybe < Account const > getCheckingAccount(Customer const &customer) { return getAccountByType(customer, Account::CHECKING); }; Maybe < Account const > getSavingsAccount(Customer const &customer) { return getAccountByType(customer, Account::SAVINGS); }; int64 const &getBalance(Account const &acct) { return acct.m_balance; } template < typename T > void print(T const &v) { std::cout << v << std::endl; } int main(int const argc, char const * const argv[]) { Customers customers = { { "12345", { "12345", { { "12345000", Account::CHECKING, 20000 }, { "12345001", Account::SAVINGS, 117000 } } } } , { "12346", { "12346", { { "12346000", Account::SAVINGS, 1000000 } } } } }; getCustomer(customers, "12346") | getCheckingAccount | getBalance | &print < int64 const >; getCustomer(customers, "12345") | getCheckingAccount | getBalance | &print < int64 const >; getCustomer(customers, "12345") | getSavingsAccount | &Account::getId | &print < std::string const >; // getCustomer(customers, "12345") | getSavingsAccount | [](Account &acct){ return acct.withdraw(100); } | &print < std::string const >; }