/* These files (monad_0,monad_2,monad_3) implement the monad examples taken from the Wadler paper "Monads for Functional Programming" found at http://cm.bell-labs.com/cm/cs/who/wadler/topics/monads.html#marktoberdorf and the examples implement variations 0, 2, and 3 as described in sections 2.5-2.9 of the paper. These files supersede monad0/monad2/monad3, now that monads and lambda are built into FC++. */ #include #include #define FCPP_ENABLE_LAMBDA #include "prelude.h" using std::cout; using std::endl; using std::pair; using std::string; using namespace fcpp; ////////////////////////////////////////////////////////////////////// // useful for variation 3 #include template string toString( const T& x ) { std::ostringstream oss; oss << x; return oss.str(); } ////////////////////////////////////////////////////////////////////// class Term { int a_; // also a Ref t_, u_; enum { Con, Div } type; public: Term( int aa ) : a_(aa), type(Con) {} Term( Ref tt, Ref uu ) : t_(tt), u_(uu), type(Div) {} bool isCon() const { return type==Con; } int a() const { if( !isCon() ) throw "oops"; return a_; } Ref t() const { if( isCon() ) throw "oops"; return t_; } Ref u() const { if( isCon() ) throw "oops"; return u_; } string asString() const { if( isCon() ) return "(Con " + toString(a()) + ")"; else return "(Div " + t()->asString() + " " + u()->asString() + ")"; } }; Ref Con( int a ) { return Ref( new Term(a) ); } Ref Div( Ref t, Ref u ) { return Ref( new Term(t,u) ); } // useful for variation 3 string xline( Ref t, int v ) { return t->asString() + " --> " + toString(v) + "\n"; } Fun2,int,string> line = ptr_to_fun(&xline); ////////////////////////////////////////////////////////////////////// struct OutputM { struct XUnit { template struct Sig : public FunType > {}; template typename Sig::ResultType operator()( const A& a ) const { return makePair( string(), a ); } }; typedef Full1 Unit; static Unit unit; struct XBind { template struct Sig : public FunType::ResultType> {}; template typename Sig::ResultType operator()( const M& m, const K& k ) const { LambdaVar<1> XA; LambdaVar<2> YB; return lambda()[ let[ XA == m, YB == k[snd[XA]] ] .in[ makePair[ fst[XA] %plus% fst[YB], snd[YB] ] ] ](); } }; typedef Full2 Bind; static Bind bind; }; OutputM::Unit OutputM::unit; OutputM::Bind OutputM::bind; Fun1 > out = makePair(_,empty); ////////////////////////////////////////////////////////////////////// typedef OutputM M; typedef pair M_int; ////////////////////////////////////////////////////////////////////// struct Eval : CFunType,M_int> { M_int operator()( Ref term ) const { if( term->isCon() ) return out(line(term,term->a())) ^bindM_()^ M::unit( term->a() ); else { LambdaVar<1> A; LambdaVar<2> B; Ref t = term->t(), u = term->u(); return lambda()[ compM()[ A %divides% B | A <= Eval()(t), B <= Eval()(u), out[line[term,A %divides% B]] ] ](); } } }; ////////////////////////////////////////////////////////////////////// Ref answer() { return Div( Div( Con(1972), Con(2) ), Con(23) ); } int main() { Eval e; M_int r = e( answer() ); cout << "(" << r.first << "," << r.second << ")" << endl; }