在c ++ 11中实现Haskell的Maybe Monad

rpg*_*rpg 23 c++ monads lambda haskell c++11

我正在尝试使用C++ 11和模板中的lambda函数从Haskell实现Maybe monad.这是我到目前为止所拥有的

#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;
}    
Run Code Online (Sandbox Code Playgroud)

说到实际的>>=调用,我收到一个编译器错误,说找不到匹配的>>=运算符.我对C++ 11的lambda函数的理解是否让我失望?

R. *_*des 8

lambda的类型不是特化std::function.这是一些非常类型的.转换为std::function,但这意味着类型扣除不适用于它.所以,在这个电话中:

Maybe<int> p = (x >>= z);
Run Code Online (Sandbox Code Playgroud)

该类型T2无法推断:

Maybe<T2> operator>>=(Maybe<T1> t, std::function < Maybe<T2> (T1)> &f)
Run Code Online (Sandbox Code Playgroud)

std::function从一开始就将lambda存储在一个变量中,它应该可以工作:

std::function < Maybe<int> (int)> z = [](int a) -> Maybe<int> { ... };
Run Code Online (Sandbox Code Playgroud)

但是,接受任何类型的函数对象可能更容易.那样你仍然可以auto用于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);
}
Run Code Online (Sandbox Code Playgroud)


J.N*_*.N. 6

以下对我有用:我使用decltype来推断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);    
  }                
}
Run Code Online (Sandbox Code Playgroud)

编辑

对于类型安全:

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");
  ...
Run Code Online (Sandbox Code Playgroud)