/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /* $Rev$ $Date$ */ #ifndef tuscany_monad_hpp #define tuscany_monad_hpp /** * Simple monad implementations. */ #include "function.hpp" #include "string.hpp" #include "stream.hpp" #include "sstream.hpp" #include "fstream.hpp" namespace tuscany { /** * Identity monad. Just wraps a value. * To get the value in the monad, just cast it to the value type. */ template class id { public: id(const V& v) : v(v) { } const id& operator=(const id& m) { if(this == &m) return *this; v = m.v; return *this; } const bool operator!=(const id& m) const { return !this->operator==(m); } const bool operator==(const id& m) const { if (&m == this) return true; return v == m.v; } private: const V v; template friend const X content(const id& m); }; /** * Write an identity monad to a stream. */ template ostream& operator<<(ostream& out, const id& m) { out << content(m); return out; } /** * Returns the content of an identity monad. */ template const V content(const id& m) { return m.v; } /** * Return an identity monad from a value. */ template const id mkunit(const V& v) { return id(v); } template const lambda(const V)> unit() { return mkunit; } /** * Bind a function to an identity monad. Pass the value in the monad to the function. */ template const id operator>>(const id& m, const lambda(const V)>& f) { return f(content(m)); } template const id operator>>(const id& m, const id (* const f)(const V)) { return f(content(m)); } /** * Maybe monad. Used to represent an optional value, which may be there or not. * To get the value in the monad, just cast it to the value type. */ template class maybe { public: maybe(const V& v) : hasv(true), v(v) { } maybe() : hasv(false) { } const maybe& operator=(const maybe& m) { if(this == &m) return *this; hasv = m.hasv; if (hasv) v = m.v; return *this; } const bool operator!=(const maybe& m) const { return !this->operator==(m); } const bool operator==(const maybe& m) const { if (this == &m) return true; if (!hasv) return !m.hasv; return m.hasv && v == m.v; } private: const bool hasv; V v; template friend const bool hasContent(const maybe& m); template friend const X content(const maybe& m); }; /** * Write a maybe monad to a stream. */ template ostream& operator<<(ostream& out, const maybe& m) { if (!hasContent(m)) { out << "nothing"; return out; } out << content(m); return out; } /** * Return a maybe monad with a value in it. */ template const maybe mkjust(const V& v) { return maybe(v); } template const lambda(const V)> just() { return mkjust; } /** * Returns true if a maybe monad contains a content. */ template const bool hasContent(const maybe& m) { return m.hasv; } /** * Returns the content of a maybe monad. */ template const V content(const maybe& m) { return m.v; } /** * Bind a function to a maybe monad. Passes the value in the monad to the function * if present, or does nothing if there's no value. */ template const maybe operator>>(const maybe& m, const lambda(const V)>& f) { if (!hasContent(m)) return m; return f(content(m)); } template const maybe operator>>(const maybe& m, const maybe (* const f)(const V)) { if (!hasContent(m)) return m; return f(content(m)); } /** * Failable monad. Used to represent either a success value or a failure. * To get the value in the monad, just cast it to the value type. * To get the failure in the monad, cast it to the failure type. */ template class failable { public: failable() : hasv(false), c(-1) { } failable(const V& v) : hasv(true), v(v), c(-1) { } failable(const failable& m) : hasv(m.hasv), v(m.v), f(m.f), c(m.c) { } const failable& operator=(const failable& m) { if (&m == this) return *this; hasv = m.hasv; v = m.v; f = m.f; c = m.c; return *this; } const bool operator!=(const failable& m) const { return !this->operator==(m); } const bool operator==(const failable& m) const { if (this == &m) return true; if (!hasv) return !m.hasv && f == m.f && c == m.c; return m.hasv && v == m.v; } private: failable(const bool hasv, const F& f, const C& c) : hasv(hasv), f(f), c(c) { } template friend const bool hasContent(const failable& m); template friend const A content(const failable& m); template friend const B reason(const failable& m); template friend const R rcode(const failable& m); template friend const failable mkfailure(const B& f, const R& c, const bool log); template friend const failable mkfailure(const B& f, const int c, const bool log); template friend const failable mkfailure(); bool hasv; V v; F f; C c; }; /** * Write a failable monad to a stream. */ template ostream& operator<<(ostream& out, const failable& m) { if (!hasContent(m)) { out << reason(m) << " : " << rcode(m); return out; } out << content(m); return out; } /** * Returns a failable monad with a success value in it. */ template const failable mksuccess(const V& v) { return failable(v); } template const lambda(const V)> success() { return mksuccess; } /** * Returns a failable monad with a failure in it. */ template const failable mkfailure(const F& f, const C& c, const bool log = true) { #ifdef WANT_MAINTAINER_LOG if (!log) debug(f, "failable::mkfailure"); #endif if (log) { ostringstream os; os << f; if (length(str(os)) != 0) cfailure << "failable::mkfailure" << ": " << f << " : " << c << endl; } return failable(false, f, c); } template const failable mkfailure(const F& f, const int c = -1, const bool log = true) { #ifdef WANT_MAINTAINER_LOG if (!log) debug(f, c, "failable::mkfailure"); #endif if (log) { ostringstream os; os << f; if (length(str(os)) != 0) cfailure << "failable::mkfailure: " << str(os) << " : " << c << endl; } return failable(false, f, c); } template const failable mkfailure(const char* f, const int c = -1, const bool log = true) { return mkfailure(string(f), c, log); } template const failable mkfailure() { return failable(false, string(), -1); } template const lambda(const V)> failure() { return mkfailure; } /** * Convert a failable of a given type to a failable of another type. */ template const failable mkfailure(const failable& f, const bool log = true) { return mkfailure(reason(f), rcode(f), log); } /** * Returns true if the monad contains a content. */ template const bool hasContent(const failable& m) { return m.hasv; } /** * Returns the content of a failable monad. */ template const V content(const failable& m) { return m.v; } /** * Returns the reason for failure of a failable monad. */ template const F reason(const failable& m) { return m.f; } /** * Returns the reason code for failure of a failable monad. */ template const C rcode(const failable& m) { return m.c; } /** * Bind a function to a failable monad. Passes the success value in the monad to the function * if present, or does nothing if there's no value and a failure instead. */ template const failable operator>>(const failable& m, const lambda(const V)>& f) { if (!hasContent(m)) return m; return f(content(m)); } template const failable operator>>(const failable& m, const failable (* const f)(const V)) { if (!hasContent(m)) return m; return f(content(m)); } /** * State + content pair data type used by the state monad. */ template class scp { public: scp(const S& s, const V& v) : s(s), v(v) { } operator const S() const { return s; } operator const V() const { return v; } const scp& operator=(const scp& p) { if(this == &p) return *this; s = p.s; v = p.v; return *this; } const bool operator!=(const scp& p) const { return !this->operator==(p); } const bool operator==(const scp& p) const { if (this == &p) return true; return s == p.s && v == p.v; } private: const S s; const V v; template friend const A scpstate(const scp& m); template friend const B content(const scp& m); }; /** * Returns the state of a state-content pair. */ template const S scpstate(const scp& m) { return m.s; } /** * Returns the content of a state-content pair. */ template const S content(const scp& m) { return m.v; } /** * State monad. Used to represent the combination of a state and a content. */ template class state { public: state(const lambda(const S)>& f) : f(f) { } const scp operator()(const S& s) const { return f(s); } const state& operator=(const state& m) { if(this == &m) return *this; f = m.f; return *this; } const bool operator!=(const state& m) const { return !this->operator==(m); } const bool operator==(const state& m) const { if (this == &m) return true; return f == m.f; } private: const lambda(const S)> f; }; /** * Write a state monad to a stream. */ template ostream& operator<<(ostream& out, const state& m) { const S s = m; const V v = m; out << '(' << s << ' ' << v << ')'; return out; } /** * Return a state monad carrying a result content. */ template struct returnState { const V v; returnState(const V& v) : v(v) { } const scp operator()(const S& s) const { return scp(s, v); } }; template const state result(const V& v) { return state(returnState(v)); } /** * Return a state monad with a transformer function. * A transformer function takes a state and returns an scp pair carrying a content and a * new (transformed) state. */ template const state transformer(const lambda(const S)>& f) { return state(f); } /** * Bind a function to a state monad. The function takes a content and returns a state * monad carrying a return content. */ template struct stateBind { const state st; const lambda(const A)>f; stateBind(const state& st, const lambda(const A)>& f) : st(st), f(f) { } const scp operator()(const S& is) const { const scp iscp = st(is); const state m = f((A)iscp); return m((S)iscp); } }; template const state operator>>(const state& st, const lambda(const A)>& f) { return state(stateBind(st, f)); } template const state operator>>(const state& st, const state (* const f)(const A)) { return state(stateBind(st, f)); } } #endif /* tuscany_monad_hpp */