Implementing Haskell's Maybe Monad in c++11

后端 未结 6 1463
星月不相逢
星月不相逢 2021-01-31 09:54

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         


        
6条回答
  •  攒了一身酷
    2021-01-31 10:51

    My 5 cts.

    Sample usage:

    Maybe m1 ("longlonglong");
    
    auto res1 = m1 | lengthy  | length;
    

    lengthy and length are "monadic lambdas", i.e.

    auto length = [] (const string & s) -> Maybe{ return Maybe (s.length()); };
    

    Complete code:

    // g++ -std=c++1y answer.cpp
    
    #include 
    using namespace std;
    
    // ..................................................
    // begin LIBRARY
    // ..................................................
    template
    class Maybe {
      // 
      //  note: move semantics
      //  (boxed value is never duplicated)
      // 
    
    private:
    
      bool is_nothing = false;
    
    public:
      T value;
    
      using boxed_type = T;
    
      bool isNothing() const { return is_nothing; }
    
      explicit Maybe () : is_nothing(true) { } // create nothing
    
      // 
      //  naked values
      // 
      explicit Maybe (T && a) : value(std::move(a)), is_nothing(false) { }
    
      explicit Maybe (T & a) : value(std::move(a)), is_nothing(false) { }
    
      // 
      //  boxed values
      // 
      Maybe (Maybe & b) : value(std::move(b.value)), is_nothing(b.is_nothing) { b.is_nothing = true; }
    
      Maybe (Maybe && b) : value(std::move(b.value)), is_nothing(b.is_nothing) { b.is_nothing = true; }
    
      Maybe & operator = (Maybe & b) {
        value = std::move(b.value);
        (*this).is_nothing = b.is_nothing;
        b.is_nothing = true;
        return (*this);
      }
    }; // class
    
    // ..................................................
    template
    auto operator | (Maybe mi, F f)  // chaining (better with | to avoid parentheses)
    {
      // deduce the type of the monad being returned ...
      IT aux;
      using OutMonadType = decltype( f(aux) );
      using OT = typename OutMonadType::boxed_type;
    
      // just to declare a nothing to return
      Maybe nothing;
    
      if (mi.isNothing()) {
        return nothing;
      }
    
      return f ( mi.value );
    } // ()
    
    // ..................................................
    template
    void showMonad (MO m) {
      if ( m.isNothing() ) {
        cout << " nothing " << endl;
      } else {
        cout << " something : ";
        cout << m.value << endl;
      }
    }
    
    // ..................................................
    // end LIBRARY
    // ..................................................
    
    // ..................................................
    int main () {
    
      auto lengthy = [] (const string & s) -> Maybe { 
        string copyS = s;
        if  (s.length()>8) {
          return Maybe (copyS);
        }
        return Maybe (); // nothing
      };
    
      auto length = [] (const string & s) -> Maybe{ return Maybe (s.length()); };
    
      Maybe m1 ("longlonglong");
      Maybe m2 ("short");
    
      auto res1 = m1 | lengthy  | length;
    
      auto res2 = m2 | lengthy  | length;
    
      showMonad (res1);
      showMonad (res2);
    
    
    } // ()
    

提交回复
热议问题