PStade.Egg.Monad で遊んでみた
Undocumented ですが,pstade/egg/monad/ 以下に Monad クラスと boost::optional をそのインスタンスとしたものがあります.実用向きとは言えませんが,ちょっと遊んでみました.
monad_optional_test.cpp
#define BOOST_RESULT_OF_USE_DECLTYPE #include <cmath> #include <iostream> #include <boost/optional/optional.hpp> #include <boost/optional/optional_io.hpp> #include <pstade/egg/infix.hpp> #include <pstade/egg/monad/optional.hpp> int main() { using namespace pstade::egg; using namespace pstade::egg::infix; std::cout << ( // return 25 >>= monad_return(25.0) ^monad_bind^ // \d -> if d >= 0 then Just (sqrt d) else Nothing [](double d) { return d >= 0.0 ? boost::make_optional(std::sqrt(d)) : boost::none; } ) << '\n'; }
出力
5.0
ラムダ式のおかげで,意外にも自然なコードになっています.
調子に乗って,State モナドも実装してみました.
monad_state/core.hpp
https://gist.github.com/1086314
monad_state/state.hpp
https://gist.github.com/1086318
monad_state_state_test.cpp
#define BOOST_RESULT_OF_USE_DECLTYPE #include <iostream> #include <pstade/egg/infix.hpp> #include <pstade/egg/monad/core.hpp> #include "./monad_state/state.hpp" int main() { using namespace pstade::egg; using namespace pstade::egg::infix; auto const v = ( // return 12 >> monad_return(12) ^monad_bind_^ ( // get >>= \s -> X_monad_state_get<state<int, int>> {} () ^monad_bind^ [](int s) { return // put (s + 1) >> monad_state_put(s + 1) ^monad_bind_^ // return s X_monad_return<state<int, int>>()(s); }) ).run_state(11); std::cout << "(" << v.first << "," << v.second << ")\n"; }
出力
(11,12)
型を明示しなければならない場所が多くて,美しくありませんね.
Expression Template の方が,型推論を上手く扱えそうです.
おまけ
Functor クラス
functor/core.hpp
https://gist.github.com/1086338
functor/optional.hpp
https://gist.github.com/1086340
functor_optional_test.cpp
#include <iostream> #include <boost/lambda/lambda.hpp> #include <boost/optional/optional.hpp> #include <boost/optional/optional_io.hpp> #include "./functor/optional.hpp" int main() { using namespace boost::lambda; std::cout << // fmap (\x -> x * x) (Just 5.0) functor_fmap(_1 * _1, boost::make_optional(5.0)) << '\n' << // fmap (\x -> x * x) (Nothing :: Maybe Double) functor_fmap(_1 * _1, boost::optional<double>()) << '\n'; }