如何获得我的可能<>的值OUT单子?

时间:2015-02-04 19:06:27

标签: c++ monads

出于教育原因,我正在尝试用C ++ 14实现一个monad monad。我对monad的理解(可能过于简单化)是它们允许您将计算定义为一系列可组合函数调用。关于monads的维基百科文章将它们称为“可编程分号”,因为它们可以让您定义在本来是一组谨慎的函数调用之间发生的事情。可能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))。问题是我无法获得最终值OUT!我试着让terminal_maybe接受一个引用(auto&amp;),这迫使我修改fmap的return语句(只返回terminal_maybe(t)而不是新的)。但它仍然没有最终printf的正确值。

1 个答案:

答案 0 :(得分:2)

这很有效,但从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;
}