Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 6646999
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 26, 20262026-05-26T00:29:08+00:00 2026-05-26T00:29:08+00:00

I repeatedly find myself requiring Haskell style Maybe (especially Maybe chaining) in my project

  • 0

I repeatedly find myself requiring Haskell style Maybe (especially Maybe chaining) in my project at work. E.g. withdrawal request from customer and we are given the customer ID… lookup customer in cache… if customer is found… lookup her savings account… if there is an account… withdraw… At any point in this chain, if there is a lookup failure, do nothing and return a failure.

My chains are large… sometimes as long as 6… so here is my swipe at Haskell.Data.Maybe in C++0x… (note… this should work in C++ if I stop using variadic templates). I have worked out chaining for free-functions taking one argument or member functions taking no arguments and I am happy with the interface. However, for functions taking multiple parameters… I have to write a lambda function to simulate partial application. Is there a way to avoid it? See the last line of main(). Even if it is uncommented it won’t compile, but for const/non-const mixing. But the question still stands.

Sorry about the large chunk of code… I hope this wouldn’t turn away people who might otherwise be interested in this…

#include <iostream>
#include <map>
#include <deque>
#include <algorithm>
#include <type_traits>

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 >;
}
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-26T00:29:08+00:00Added an answer on May 26, 2026 at 12:29 am

    Good start, but I think you’re over-engineering in your zeal to make your class foolproof. Personally I’d recommend ‘worse is better’. First, let’s reuse Boost.Optional:

    struct nothing_type {
        template<typename T>
        operator boost::optional<T>() const
        { return {}; }
    };
    constexpr nothing_type nothing;
    
    template<typename T>
    boost::optional<T>
    just(T&& t)
    {
        return std::forward<T>(t);
    }
    
    template<typename Option, typename Functor>
    auto maybe_do(Option&& option, Functor&& functor)
    -> boost::optional<
        decltype( functor(*std::forward<Option>(option)) )
    >
    {
        // Forwarding 
        if(option)
            return functor(*std::forward<Option>(option));
        else
            return nothing;
    }
    

    Some various explanations on things that aren’t really important:

    • nothing doesn’t have to be an object, it can still be a function (returning nothing_type) like you’re doing. That’s not important.

    • I made sure to preserve the reference semantics of just to match your version. As a bonus though, it can still deal with values. As such, with int i = 0; auto maybe = just(i); then the type of maybe will be boost::optional<int&>, whereas with auto maybe = just(42); it is boost::optional<int>.

    • the *std::forward<Option>(option) can actually simply be *option as Boost.Optional is not move-aware and not many compilers support lvalue/rvalue *this (which would be needed for it to matter). I just like future-proofing perfect-forwarding templates.

    • you can still name maybe_do operator| instead. I would however recommend putting it in a namespace and use using ns::operator| (or using namespace ns;) to put it into scope. You can additionally (or instead) add an SFINAE check (or write several overloads) to make sure it only participates in overload resolution at appropriate times. I’m advising this to avoid namespace pollution and annoying errors.

    The important stuff:

    It may look like maybe_do is severely underpowered compared to your overloads that can deal with member pointers. But I’d recommend keeping it simple and instead putting the burden on client-code to adapt member pointers:

    auto maybe = /* fetch an optional<T cv ref> from somewhere */
    maybe_do(maybe, std::bind(&T::some_member, _1));
    

    Similarly client code can use std::bind to do the poor man’s partial evaluation:

    maybe_do(maybe, std::bind(some_functor, _1, "foo", _2, bar));
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I find myself repeatedly looking for a clear definition of the differences of nil?
While using Vim (at home and at work), I often find myself doing similar
I often find myself repeatedly yanking something after doing some kills and it becomes
I'm relatively new to JavaScript and repeatedly find myself writing methods in a helper
I find myself doing this repeatedy. $jq(button).filter(function(){ return this.id.match(/^user_(\d+)_edit$/); }).click(function(){ var matches = this.id.match(/^user_(\d+)_edit$/);
Maybe is a often repeated question here, but i can't find anything similar with
I've installed cx_Oracle (repeatedly) and I just can't get it to work on my
I find myself frequently repeating HTML code to format items such as lists, tables,
Forgive me if this has been asked repeatedly, but I couldn't find an example
I often find myself writing a property that is evaluated lazily. Something like: if

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.