/** * Copyright @CanftIn 2020 * LICENSE: GPL-v3.0 **/ #ifndef __CPPMONAD_H__ #define __CPPMONAD_H__ #include #include #include #include #include #include #include #include #include #include template using Vec = std::vector; template using List = std::list; template using Map = std::map; template using Maybe = boost::optional; template using Either = boost::variant; template using Function = std::function; template using Endomorphism = Function; typedef std::string String; template T id(T x) { return x; } // (b -> c) -> (a -> b) -> a -> c template Function compose(Function f, Function g) { using namespace std::placeholders; return std::bind(f, std::bind(g, _1)); } // class template class Functor; // functions // Functor a => (b -> c) -> a b -> a c template inline typename Functor::template F fmap(Function const& f, FA const& fa) { return Functor::template fmap(f, fa); } // instances template class Functor> { public: template using F = Vec; template static Vec fmap(Function const& f, Vec const& as) { Vec bs; bs.reserve(as.size()); std::back_insert_iterator> bi(bs); std::transform(as.begin(), as.end(), bi, f); return bs; } }; template class Functor> { public: template using F = List; template static List fmap(Function const& f, List const& as) { List bs; std::back_insert_iterator> bi(bs); std::transform(as.begin(), as.end(), bi, f); return bs; } }; template class Functor> { public: template using F = Map; template static Map fmap(Function const& f, Map const& as) { Map bs; for (auto const& ka : as) bs.insert(ka.first, f(ka.second)); return bs; } }; template class Functor> { public: template using F = Maybe; template static F fmap(Function const& f, Maybe const& ma) { return ma ? f(*ma) : F(); } }; template class Functor> { public: template using F = Either; template static F fmap(Function const& f, Either const& ab) { A const* a = boost::get(ab); B const* b = boost::get(ab); return a ? *a : f(*b); } }; template class Functor> { public: template using F = Function; template static F fmap(Function const& f, Function const& ab) { return compose(f, ab); } }; // class template class Monoid; // functions template inline A empty() { return Monoid::empty(); } template inline A append(A const& x, A const& y) { return Monoid::append(x, y); } template inline A concat(I b, I e) { return std::accumulate(b, e, empty(), append); } template inline A concat(C const& xs) { return concat(xs.begin(), xs.end()); } // instances template class Monoid> { public: static Vec empty() { return Vec(); } static Vec append(Vec const& x, Vec const& y) { Vec res; res.reserve(x.size() + y.size()); res.insert(res.end(), x.begin(), x.end()); res.insert(res.end(), y.begin(), y.end()); return res; } }; template class Monoid> { public: static List empty() { return List(); } static List append(List const& x, List const& y) { List res; res.insert(res.end(), x.begin(), x.end()); res.insert(res.end(), y.begin(), y.end()); return res; } }; template class Monoid> { public: static Map empty() { return Map(); } static Map append(Map const& x, Map const& y) { Map res; res.insert(x.begin(), x.end()); res.insert(y.begin(), y.end()); return res; } }; template <> class Monoid { public: static String empty() { return String(); } static String append(String const& a, String const& b) { return a + b; } }; // class template class Monad; // Monad a => a -> m a template inline MA mreturn(A const& a) { return Monad::mreturn(a); } // Monad a => a b -> (b -> a c) -> a c template inline MB operator >>= (MA const& ma, Function const& f) { return Monad::bind(ma, f); } // Monad a => a b -> a c -> a c template inline MB operator >> (MA const& ma, MB const& mb) { using A = typename Monad::Type; Function f = [=](A const&){ return mb; }; return ma >>= f; } // instances template class Monad> { public: typedef A Type; static Vec mreturn(A const& a) { return Vec { a }; } template static Vec bind(Vec const& as, Function> const& f) { Vec bs; bs.reserve(as.size()); for (auto const& a : as) for (auto const& b : f(a)) bs.push_back(b); return bs; } }; template class Monad> { public: typedef A Type; static Maybe mreturn(A const& a) { return Maybe(a); } template static Maybe bind(Maybe const& ma, Function> const& f) { return ma ? f(*ma) : Maybe(); } }; template class Monad> { public: typedef B Type; static Either mreturn(B const& b) { return Either(b); } template static Either bind(Either const& mb, Function> const& f) { A const* a = boost::get(&mb); B const* b = boost::get(&mb); return a ? *a : f(*b); } }; template class Monad> { public: typedef B Type; static Function mreturn(B const& b) { return [=](A const&){ return b; }; } template static Function bind(Function const& mb, Function> const& f) { return [=](A a){ return f(mb(a))(a); }; } }; // class template class Show { public: static String show(A const& x) { return boost::lexical_cast(x); } }; // functions template inline String show(A const& x) { return Show::show(x); } // instances template <> class Show { public: static String show(String const& s) { return '"' + s + '"'; } }; template class Show> { public: static String show(Vec const& xs) { String res = ""; for (auto const& x : xs) res += ", " + Show::show(x); return "[" + res.erase(0, 2) + "]"; } }; template class Show> { public: static String show(List const& xs) { String res = ""; for (auto const& x : xs) res += ", " + Show::show(x); return "[" + res.erase(0, 2) + "]"; } }; template class Show> { public: static String show(List const& xs) { String res = ""; for (auto const& x : xs) res += ", " + Show::show(x.first) + ": " + Show::show(x.second); return "{" + res.erase(0, 2) + "}"; } }; template class Show> { public: static String show(Maybe const& x) { return x ? "Just " + Show::Show::show(*x) : "Nothing"; } }; template class Show> { public: static String show(Either const& x) { return boost::apply_visitor(EitherShow(), x); } private: class EitherShow : public boost::static_visitor { public: String operator()(A const& a) const { return "Left " + Show::show(a); } String operator()(B const& b) const { return "Right " + Show::show(b); } }; }; #endif