読者です 読者をやめる 読者になる 読者になる

テンプレートメタプログラミングでMaybeモナド

C++

階層化された型リスト」で、連続したメタ関数の適用が書きやすくなったので
Maybeモナドもいけるかな、と思って作ってみました。

#include <iostream>
#include <boost/type_traits.hpp>
#include <boost/mpl/if.hpp>

template <class T>
struct just;

struct nothing;

template <class T>
struct return_ {
    typedef just<T> type;
};

template <class T>
struct return_<just<T> > {
    typedef just<T> type;
};

template <class T>
class maybe {
    template <class Maybe>
    struct is_integral_;

    template <class T>
    struct is_integral_<just<T> > {
        typedef typename
            boost::mpl::if_<
                boost::is_integral<T>,
                maybe<just<T> >,
                maybe<nothing>
            >::type
        type;
    };

    template <>
    struct is_integral_<nothing> {
        typedef maybe<nothing> type;
    };

    template <class>
    struct fail_ {
        typedef maybe<nothing> type;
    };

    template <class Maybe>
    struct success_;

    template <class T>
    struct success_<just<T> > {
        typedef maybe<just<T> > type;
    };

    template <>
    struct success_<nothing> {
        typedef maybe<nothing> type;
    };

public:
    typedef typename is_integral_<T>::type is_integral;
    typedef typename fail_<T>::type        fail;
    typedef typename success_<T>::type     success;
    typedef typename T                     result;
};


template <class Maybe>
struct print;

template <class T>
struct print<just<T> > {
    void operator()() const
    {
        std::cout << typeid(T).name() << std::endl;
    }
};

template <>
struct print<nothing> {
    void operator()() const
    {
        std::cout << "nothing" << std::endl;
    }
};

int main()
{
    print<maybe<return_<int>::type>::is_integral::result>()();                // int
    print<maybe<return_<int>::type>::is_integral::fail::result>()();          // nothing
    print<maybe<return_<int>::type>::is_integral::fail::success::result>()(); // nothing

    print<maybe<return_<void>::type>::is_integral::result>()();               // nothing
    print<maybe<return_<void>::type>::is_integral::success::result>()();      // nothing
}

連続したメタ関数適用のうち、途中でnothingが返ったらその後のメタ関数適用は全てnothingが返り、
全て成功したときのみjustが返ります。


return_は型Tをjustに変換します。
is_integralは整数型だったらjust、それ以外はnothingを返します。
failは問答無用でnothing(失敗)を返します。
successはjust(成功していたら)だったらjust、それ以外はnothingを返します。



【追記:2009/12/05 22:43】
GCC 4.xで動かないという報告をいただいたので修正しました。

#include <iostream>
#include <typeinfo>
#include <boost/type_traits.hpp>
#include <boost/mpl/if.hpp>

template <class T>
struct just;

struct nothing;

template <class T>
struct return_ {
    typedef just<T> type;
};

template <class T>
struct return_<just<T> > {
    typedef just<T> type;
};

template <class T>
class maybe {
    template <class Maybe>
    struct is_integral_ {
        typedef maybe<nothing> type;
    };

    template <class T1>
    struct is_integral_<just<T1> > {
        typedef typename
            boost::mpl::if_<
                boost::is_integral<T1>,
                maybe<just<T1> >,
                maybe<nothing>
            >::type
        type;
    };

    template <class>
    struct fail_ {
        typedef maybe<nothing> type;
    };

    template <class Maybe>
    struct success_ {
        typedef maybe<nothing> type;
    };

    template <class T1>
    struct success_<just<T1> > {
        typedef maybe<just<T1> > type;
    };

public:
    typedef typename is_integral_<T>::type is_integral;
    typedef typename fail_<T>::type        fail;
    typedef typename success_<T>::type     success;
    typedef T                              result;
};


template <class Maybe>
struct print;

template <class T>
struct print<just<T> > {
    void operator()() const
    {
        std::cout << typeid(T).name() << std::endl;
    }
};

template <>
struct print<nothing> {
    void operator()() const
    {
        std::cout << "nothing" << std::endl;
    }
};

int main()
{
    print<maybe<return_<int>::type>::is_integral::result>()();                // int
    print<maybe<return_<int>::type>::is_integral::fail::result>()();          // nothing
    print<maybe<return_<int>::type>::is_integral::fail::success::result>()(); // nothing

    print<maybe<return_<void>::type>::is_integral::result>()();               // nothing
    print<maybe<return_<void>::type>::is_integral::success::result>()();      // nothing
}