Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing Haskell's Maybe Monad in c++11

Tags:

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<functional> #include<iostream> using namespace std;  template<typename T1> struct Maybe {   T1 data;   bool valid; };  template<typename T1, typename T2> Maybe<T2> operator>>=(Maybe<T1> t, std::function < Maybe<T2> (T1)> &f) {   Maybe<T2> return_value;   if(t.valid == false)   {             return_value.valid = false;     return return_value;   }   else   {             return f(t.data);   }             }   int main() {   Maybe<int> x = {5, true};   Maybe<int> y = {29, false};    auto z = [](int a) -> Maybe<int>     {       Maybe<int> s;       s.data = a+1;       s.valid = true;       return s;     };    Maybe<int> p = (x >>= z);   Maybe<int> q = (y >>= z);    cout<<p.data<<' '<<p.valid<<endl;           cout<<q.data<<' '<<q.valid<<endl; }     

When it comes to the actual >>= call, I am getting a compiler error saying that no match found for >>= operator. Is my understanding of C++11's lambda functions failing me here?

like image 660
rpg Avatar asked Mar 13 '12 21:03

rpg


People also ask

Does c++ have monads?

C++ isn't a functional language but it has a strong type template system, which allows us to easily implement generic monads via template specialisation.

Is std :: Optional A monad?

Abstract. std::optional is an important vocabulary type in C++17. Some uses of it are verbose and would benefit from operations which allow functional composition. I propose adding transform, and_then, and or_else member functions to std::optional to support this monadic style of programming.

What is maybe monad?

The Maybe monad represents computations which might "go wrong" by not returning a value.

What is a monad in C++?

In functional programming, a monad is a software design pattern with a structure that combines program fragments (functions) and wraps their return values in a type with additional computation.


2 Answers

The type of a lambda isn't a specialization of std::function. It's some unamed type. There is a conversion to std::function, but that means type deduction won't work for it. So, in this call:

Maybe<int> p = (x >>= z); 

The type T2 can't be deduced:

Maybe<T2> operator>>=(Maybe<T1> t, std::function < Maybe<T2> (T1)> &f) 

Store the lambda in a std::function variable from the start, and it should work:

std::function < Maybe<int> (int)> z = [](int a) -> Maybe<int> { ... }; 

However, it's probably easier to accept any kind of function object. That way you can still use auto for the lambda.

template<typename T1, typename F> typename std::result_of<F(T1)>::type operator>>=(Maybe<T1> t, F&& f) {     ... std::forward<F>(f)(t.data); } 
like image 100
R. Martinho Fernandes Avatar answered Sep 20 '22 17:09

R. Martinho Fernandes


The following works for me: I use decltype to infer the type returned by the lambda:

template<typename T1, typename Func>     auto operator>>=(Maybe<T1> t, Func f) -> decltype(f(t.data)) {       decltype(f(t.data)) return_value;       if(t.valid == false)       {                 return_value.valid = false;         return return_value;       }       else       {                 return f(t.data);       }                 } 

EDIT

For type safety :

template<typename T1>     struct Maybe     {       T1 data;       bool valid;    static const bool isMaybe = true; };  template<typename T1, typename Func>      auto operator>>=(Maybe<T1> t, Func f) -> decltype(f(t.data))  {   typedef decltype(f(t.data)) RT;   static_assert(RT::isMaybe, "F doesn't return a maybe");   ... 
like image 44
J.N. Avatar answered Sep 20 '22 17:09

J.N.