TMP で Maybe モナド

namespace monad
{
namespace maybe
{
    struct nothing { };
    template<class A>
    struct just { };

    template<class A>
    struct ret { typedef just<A> type; };

    template<class M, template<class> class F>
    struct bind;
    template<class A, template<class> class F>
    struct bind<just<A>, F>
    {
        typedef typename F<A>::type type;
    };
    template<template<class> class F>
    struct bind<nothing, F>
    {
        typedef nothing type;
    };
}
}

定義を見ながら作るだけなのでこれは簡単。


例が思いつかなかったので C++でMaybeモナドを返すlookup関数を作ってみた - Faith and Brave - C++で遊ぼう のおまけを参考にしてみました。

template<class A>
struct inc;

template<int N>
struct inc<int_<N>>
{
    typedef typename if_<bool_<(N >= 10)>, monad::maybe::nothing, typename monad::maybe::ret<int_<N + 1>>::type>::type type;
};

int main()
{
    using namespace monad::maybe;
    typedef int_<8> value;
    typedef bind<ret<value>::type, inc>::type ret1;
    typedef bind<bind<ret<value>::type, inc>::type, inc>::type ret2;
    typedef bind<bind<bind<ret<value>::type, inc>::type, inc>::type, inc>::type ret3;
    typedef bind<bind<bind<bind<ret<value>::type, inc>::type, inc>::type, inc>::type, inc>::type ret4;

    static_assert(is_same<just<int_<9>>, ret1>::value, "failed");
    static_assert(is_same<just<int_<10>>, ret2>::value, "failed");
    static_assert(is_same<nothing, ret3>::value, "failed");
    static_assert(is_same<nothing, ret4>::value, "failed");
}

operator>>= が使えないといろいろ無理がある気がする……。