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函数的理解是否让我失望?
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)
以下对我有用:我使用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)