По образовательным причинам я пытаюсь реализовать, возможно, монаду в C ++ 14. Мое (возможно, чрезмерно упрощенное) понимание монад заключается в том, что они позволяют вам определять вычисления как серию вызовов составных функций. Статья в википедии о монадах называет их «программируемые точки с запятой», потому что они позволяют вам определить, что происходит между тем, что в противном случае было бы набором дискретных вызовов функций. Возможно, монада — это монада, которая прерывает вычисления в случае сбоя.
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)). Проблема в том, что у меня нет возможности получить окончательное значение OUT! Я попытался заставить Terminal_maybe принять ссылку (авто&) и это заставило меня изменить оператор возврата fmap (просто вернуть Terminal_maybe (t), а не возможно новое). Но это все еще не имело правильное значение для окончательного 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;
}