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?
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.
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.
The Maybe monad represents computations which might "go wrong" by not returning a value.
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.
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); }
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"); ...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With