我如何从我的 maybe<> monad 中获取价值?
How do I get the value OUT of my maybe<> monad?
出于教育原因,我正在尝试在 C++14 中实现一个 maybe monad。我(也许过于简单化)对 monad 的理解是,它们允许您将计算定义为一系列可组合的函数调用。维基百科关于 monads 的文章称它们为 "programmable semicolons" 因为它们可以让你定义在一组谨慎的函数调用之间会发生什么。 maybe monad 是一个在发生故障时中断计算的 monad。
template<class T>
struct maybe
{
maybe( const T& t ) : argument( t ), valid( true ) {}
maybe() : argument(), valid( false ) {}
T argument;
bool valid;
};
template<class T>
maybe<T> just( const T& t ) { return maybe<T>(t); }
template<class T>
maybe<T> nothing() { return maybe<T>(); }
auto terminal_maybe = [] ( auto term ) {
return [=] ( auto func ) {
return func( term );
};
};
auto fmap_maybe = [] ( auto f ) {
return [=] ( auto t ) {
if( t.valid ) {
try {
t.argument = f( t.argument );
printf("argument = %d\n",t.argument);
}
catch(...) {
t.valid = false;
}
}
return (t.valid) ? terminal_maybe( just( t.argument ) ) : terminal_maybe( nothing<decltype(t.argument)>() );
};
};
int main( int argc, char* argv[] )
{
auto plus_2 = [] ( auto arg ) { return arg + 2; };
auto minus_2 = [] ( auto arg ) { return arg - 2; };
maybe<int> forty = just(40);
terminal_maybe(forty)
(fmap_maybe( plus_2 ))
(fmap_maybe( plus_2 ));
printf("result = %d\n",forty.argument);
return 0;
}
如你所见,我超级亲近!我可以单次将多个调用链接在一起(我可以从 printf 中看出我的值符合我的预期(从 40 增加到 42,然后从 42 增加到 44))。问题是我没有办法得到最终的价值!我尝试让 terminal_maybe 接受引用 (auto&),这迫使我修改 fmap 的 return 语句(只修改为 return terminal_maybe( t ) 而不是新的 maybe)。但它仍然没有最终 printf 的正确值。
这行得通,但我不知道从 FP 的角度来看是否有意义。
auto unwrap = [](auto const &f) {
return f;
};
int main( int argc, char* argv[] )
{
auto plus_2 = [] ( auto arg ) { return arg + 2; };
auto minus_2 = [] ( auto arg ) { return arg - 2; };
maybe<int> forty = just(40);
auto const &outv = terminal_maybe(forty)
(fmap_maybe( plus_2 ))
(fmap_maybe( plus_2 ))
(unwrap);
std::printf("result = %d\n",outv.argument);
return 0;
}
出于教育原因,我正在尝试在 C++14 中实现一个 maybe monad。我(也许过于简单化)对 monad 的理解是,它们允许您将计算定义为一系列可组合的函数调用。维基百科关于 monads 的文章称它们为 "programmable semicolons" 因为它们可以让你定义在一组谨慎的函数调用之间会发生什么。 maybe monad 是一个在发生故障时中断计算的 monad。
template<class T>
struct maybe
{
maybe( const T& t ) : argument( t ), valid( true ) {}
maybe() : argument(), valid( false ) {}
T argument;
bool valid;
};
template<class T>
maybe<T> just( const T& t ) { return maybe<T>(t); }
template<class T>
maybe<T> nothing() { return maybe<T>(); }
auto terminal_maybe = [] ( auto term ) {
return [=] ( auto func ) {
return func( term );
};
};
auto fmap_maybe = [] ( auto f ) {
return [=] ( auto t ) {
if( t.valid ) {
try {
t.argument = f( t.argument );
printf("argument = %d\n",t.argument);
}
catch(...) {
t.valid = false;
}
}
return (t.valid) ? terminal_maybe( just( t.argument ) ) : terminal_maybe( nothing<decltype(t.argument)>() );
};
};
int main( int argc, char* argv[] )
{
auto plus_2 = [] ( auto arg ) { return arg + 2; };
auto minus_2 = [] ( auto arg ) { return arg - 2; };
maybe<int> forty = just(40);
terminal_maybe(forty)
(fmap_maybe( plus_2 ))
(fmap_maybe( plus_2 ));
printf("result = %d\n",forty.argument);
return 0;
}
如你所见,我超级亲近!我可以单次将多个调用链接在一起(我可以从 printf 中看出我的值符合我的预期(从 40 增加到 42,然后从 42 增加到 44))。问题是我没有办法得到最终的价值!我尝试让 terminal_maybe 接受引用 (auto&),这迫使我修改 fmap 的 return 语句(只修改为 return terminal_maybe( t ) 而不是新的 maybe)。但它仍然没有最终 printf 的正确值。
这行得通,但我不知道从 FP 的角度来看是否有意义。
auto unwrap = [](auto const &f) {
return f;
};
int main( int argc, char* argv[] )
{
auto plus_2 = [] ( auto arg ) { return arg + 2; };
auto minus_2 = [] ( auto arg ) { return arg - 2; };
maybe<int> forty = just(40);
auto const &outv = terminal_maybe(forty)
(fmap_maybe( plus_2 ))
(fmap_maybe( plus_2 ))
(unwrap);
std::printf("result = %d\n",outv.argument);
return 0;
}