// The program here is based on an example from // "Designing and Implementing Combinator Languages" // by S. Doaitse Swierstra, Pablo R. Azero Alcocer, Joao Saraiva #include #include #include #include #include "prelude.h" using std::vector; using std::cin; using std::cerr; using std::cout; using std::endl; using namespace fcpp; #ifndef N #define N 1000 #endif #ifdef REAL_TIMING # include "timer.h" #else struct Timer { int ms_since_start() { return 0; } }; #endif int the_count; class Tree { int data_; Tree *left_; Tree *right_; bool pr_leaf() const { return (left_==0) && (right_==0); } public: Tree( int x ) : data_(x), left_(0), right_(0) {} Tree( Tree* l, Tree* r ) : data_(0), left_(l), right_(r) {} bool leaf() const { ++the_count; return pr_leaf(); } int data() const { if( !pr_leaf() ) throw "bad"; return data_; } Tree* left() const { if( pr_leaf() ) throw "bad"; return left_; } Tree* right() const { if( pr_leaf() ) throw "bad"; return right_; } }; int sum_tree( Tree* root ) { if( root->leaf() ) return root->data(); else return sum_tree( root->left() ) + sum_tree( root->right() ); } ////////////////////////////////////////////////////////////////////// template struct TreeAlgebra { typedef A Type; Fun1 leaf; Fun2 bin; TreeAlgebra( Fun1 a, Fun2 b ) : leaf(a), bin(b) {} }; struct CataTree { template struct Sig : public FunType {}; template A operator()( const TreeAlgebra& alg, Tree* t ) const { if( t->leaf() ) return alg.leaf( t->data() ); else return alg.bin( CataTree()(alg,t->left()), CataTree()(alg,t->right()) ); } } cata_tree_; Curryable2 cata_tree(cata_tree_); ////////////////////////////////////////////////////////////////////// // obvious solution (Listing 3) TreeAlgebra sum_alg( id, fcpp::plus ); TreeAlgebra min_alg( id, fcpp::min ); TreeAlgebra > rep_alg( ignore(New1()), fcpp::compose2(New2()) ); Tree* replace_min1( Tree* t ) { return cata_tree(rep_alg,t)( cata_tree(min_alg,t) ); } ////////////////////////////////////////////////////////////////////// // tupling solution (Listing 4) struct TupleTree { template struct Helper { TreeAlgebra x; TreeAlgebra y; Helper( const TreeAlgebra& xx, const TreeAlgebra& yy ) : x(xx), y(yy) {} template struct Sig : public FunType > {}; template typename Sig::ResultType operator()( const L& l, const R& r ) const { return makePair(x.bin(fst(l),fst(r)),y.bin(snd(l),snd(r))); } }; template struct Sig : public FunType > > {}; template TreeAlgebra > operator()( const TreeAlgebra& x, const TreeAlgebra& y ) const { return TreeAlgebra >( fcpp::compose2( makePair, x.leaf, y.leaf ), makeCurryable2( Helper(x,y) ) ); } } tuple_tree_; Curryable2 tuple_tree(tuple_tree_); TreeAlgebra > > min_tup_rep( tuple_tree(min_alg,rep_alg) ); Tree* replace_min2( Tree* t ) { std::pair > res = cata_tree(min_tup_rep,t); return res.second( res.first ); } ////////////////////////////////////////////////////////////////////// // merging tupled functions (Listing 5) // In comments here is the typechecking-but-failing solution /* struct Yadda : public CFunType >, Fun1 >,int,std::pair > { std::pair operator()( Fun1 > lfun, Fun1 > rfun, int m ) const { std::pair lres( lfun(m) ); std::pair rres( rfun(m) ); return makePair( fcpp::min(lres.first,rres.first), new Tree(lres.second,rres.second) ); } } yadda_; Curryable3 yadda(yadda_); TreeAlgebra > > merged_alg( flip(uncurry(compose(flip(makePair),New1()))), yadda ); // FIX THIS: Circularity below, using uninitialized "res.first" Tree* replace_min3( Tree* t ) { std::pair res = cata_tree(merged_alg,t)( res.first ); return res.second; } */ // The real solution requires "full laziness" and was quite the // pain-in-the-neck to get working. :) template struct XTreeAlgebra { typedef A Type; Fun1,A> leaf; Fun2 bin; XTreeAlgebra( Fun1,A> a, Fun2 b ) : leaf(a), bin(b) {} }; struct XCataTree { template struct Sig : public FunType {}; template A operator()( const XTreeAlgebra& alg, Tree* t ) const { if( t->leaf() ) return alg.leaf( const_(t->data()) ); else return alg.bin( XCataTree()(alg,t->left()), XCataTree()(alg,t->right()) ); } } xcata_tree_; Curryable2 xcata_tree(xcata_tree_); template class Wisher { F f; public: Wisher( const F& ff ) : f(ff) {} template struct Sig : public FunType::ResultType, typename RT::ResultType>::ResultType> {}; template typename Sig::ResultType operator()( const X& x, const Y& y ) const { return f( x(), y() ); } }; template Wisher wish( const F& f ) { return Wisher(f); } struct Yadda : public CFunType, std::pair, Fun0 > >, Fun1, std::pair, Fun0 > >, Fun0,std::pair,Fun0 > > { std::pair,Fun0 > operator()( Fun1,std::pair,Fun0 > > lfun, Fun1,std::pair,Fun0 > > rfun, Fun0 m ) const { std::pair, Fun0 > lres( lfun(m) ); std::pair, Fun0 > rres( rfun(m) ); return makePair( curry2(wish(fcpp::min),lres.first,rres.first), curry2(wish(New2()),lres.second,rres.second) ); } } yadda_; Curryable3 yadda(yadda_); struct Blah : public CFunType,Fun0,std::pair,Fun0 > > { std::pair,Fun0 > operator()( Fun0 i, Fun0 m ) const { return makePair( i, Compose0()(New1(),m) ); } } blah_; Curryable2 blah(blah_); XTreeAlgebra,std::pair,Fun0 > > > merged_alg( blah, yadda ); template class Invoker : public CFunType::ResultType>::ResultType> { F thunk; public: Invoker( const F& f ) : thunk(f) {} typename RT::ResultType>::ResultType operator()() const { return thunk()(); } }; template Invoker invoke( const F& f ) { return Invoker(f); } class TheResult : public CFunType,Fun0 > > { Tree* t; public: TheResult( Tree* tt ) : t(tt) {} std::pair,Fun0 > operator()() const { static std::pair,Fun0 > res = xcata_tree(merged_alg,t)( invoke( Compose0()(fst,*this) ) ); return res; } }; Tree* replace_min3( Tree* t ) { return TheResult(t)().second(); } ////////////////////////////////////////////////////////////////////// int main() { Tree *t = new Tree( new Tree(3), new Tree( new Tree(4), new Tree(5) ) ); t = new Tree( t, t ); t = new Tree( t, t ); t = new Tree( t, t ); t = new Tree( t, t ); /* Move this window around to change the tree size t = new Tree( t, t ); t = new Tree( t, t ); */ cout << "Sum nodes is " << sum_tree(t) << endl; cout << "Sum nodes is " << cata_tree(sum_alg,t) << endl; Tree *tmp; Timer timer; int start, end; // warm up the cache tmp = replace_min1(t); cout << "After repl_min1, sum is " << sum_tree(tmp) << endl; start = timer.ms_since_start(); for( int i=0; i