// // Copyright (c) 2000-2003 Brian McNamara and Yannis Smaragdakis // // Permission to use, copy, modify, distribute and sell this software // and its documentation for any purpose is granted without fee, // provided that the above copyright notice and this permission notice // appear in all source code copies and supporting documentation. The // software is provided "as is" without any express or implied // warranty. #ifndef FCPP_PRELUDE_DOT_H #define FCPP_PRELUDE_DOT_H ////////////////////////////////////////////////////////////////////// // Note that this header file includes all the other FC++ header files, // so including this one (prelude.h) is sufficient to suck in the whole // library. ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// // Here we define a bunch of functions from the Haskell Standard // Prelude (HSP). For documentation of their behaviors, see // http://haskell.org/onlinereport/standard-prelude.html // // A number of the functions are not from HSP, but seemed natural/useful. // // The implementations #ifdef-ed out (FCPP_SIMPLE_PRELUDE) are mostly // just here to look at, as they are often more readable than their // optimized counterparts. ////////////////////////////////////////////////////////////////////// #include "list.h" namespace fcpp { namespace impl { struct XId { template struct Sig : public FunType {}; template T operator()( const T& x ) const { return x; } }; } typedef Full1 Id; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Id id; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { template class XCompose0Helper : public CFunType< typename F::template Sig::ResultType>::ResultType> { F f; G g; public: XCompose0Helper( const F& a, const G& b ) : f(a), g(b) {} typename F::template Sig::ResultType>::ResultType operator()() const { return f( g() ); } }; template class XCompose1Helper { F f; G g; public: XCompose1Helper( const F& a, const G& b ) : f(a), g(b) {} template struct Sig : public FunType< typename RT::Arg1Type, typename RT::ResultType>::ResultType> {}; template typename Sig::ResultType operator()( const X& x ) const { return f( g(x) ); } }; template class XCompose2Helper { F f; G g; public: XCompose2Helper( const F& a, const G& b ) : f(a), g(b) {} template struct Sig : public FunType< typename RT::Arg1Type, typename RT::Arg2Type, typename RT::ResultType>::ResultType> {}; template typename Sig::ResultType operator()( const X& x, const Y& y ) const { return f( g(x,y) ); } }; template class XCompose3Helper { F f; G g; public: XCompose3Helper( const F& a, const G& b ) : f(a), g(b) {} template struct Sig : public FunType< typename RT::Arg1Type, typename RT::Arg2Type, typename RT::Arg3Type, typename RT::ResultType>::ResultType> {}; template typename Sig::ResultType operator()( const X& x, const Y& y, const Z& z ) const { return f( g(x,y,z) ); } }; // Compose is Haskell's operator (.) // compose(f,g)(x,y,z) = f( g(x,y,z) ) class XCompose { template struct Helper; template struct Helper<0,F,G> { typedef Full0 > Result; static Result go( const F& f, const G& g ) { return makeFull0(XCompose0Helper(f,g)); } }; template struct Helper<1,F,G> { typedef Full1 > Result; static Result go( const F& f, const G& g ) { return makeFull1(XCompose1Helper(f,g)); } }; template struct Helper<2,F,G> { typedef Full2 > Result; static Result go( const F& f, const G& g ) { return makeFull2(XCompose2Helper(f,g)); } }; template struct Helper<3,F,G> { typedef Full3 > Result; static Result go( const F& f, const G& g ) { return makeFull3(XCompose3Helper(f,g)); } }; public: template struct Sig : public FunType::max_args,F,G>::Result> {}; template typename Sig::ResultType operator()( const F& f, const G& g ) const { return Helper::max_args,F,G>::go( f, g ); } }; } typedef Full2 Compose; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Compose compose; FCPP_MAYBE_NAMESPACE_CLOSE ////////////////////////////////////////////////////////////////////// // Now we can create "of", so that // f ^of^ g // means // compose( funify(f), funify(g) ) ////////////////////////////////////////////////////////////////////// namespace impl { struct XOf { template struct Sig : public FunType::ResultType, typename RT::ResultType>::ResultType> {}; template typename Sig::ResultType operator()( const F& f, const G& g ) const { return compose( funify(f), funify(g) ); } }; } typedef Full2 Of; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Of of; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { template class XXCompose2Helper { F f; G g; H h; public: XXCompose2Helper( const F& a, const G& b, const H& c) : f(a), g(b), h(c) {} template struct Sig : public FunType< typename G::template Sig::Arg1Type, typename F::template Sig::ResultType, typename H::template Sig::ResultType>::ResultType > {}; template typename F::template Sig::ResultType, typename H::template Sig::ResultType>::ResultType operator()( const T& x ) const { return f( g(x), h(x) ); } }; // compose2(f,g,h)(x) == f( g(x), h(x) ) // Compose2 composes a two argument function with two one-argument // functions (taking the same type). This is quite useful for the // common case of binary operators. Use lambda for more-complicated stuff. struct XCompose2 { template struct Sig : public FunType > > {}; template Full1 > operator()(const F& f, const G& g, const H& h) const { return makeFull1( XXCompose2Helper( f, g, h ) ); } }; } typedef Full3 Compose2; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Compose2 compose2; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XUntil { template struct Sig : public FunType {}; template T operator()( const Pred& p, const Unary& op, T start ) const { while( !p(start) ) { T tmp( start ); start.~T(); new (&start) T( op(tmp) ); } return start; } }; } typedef Full3 Until; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Until until; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XLast { template struct Sig : public FunType {}; template typename L::ElementType operator()( const L& ll ) const { List l = ll; while( !null( tail(l) ) ) l = tail(l); return head(l); } }; } typedef Full1 Last; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Last last; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { #ifdef FCPP_SIMPLE_PRELUDE struct XInit { template struct Sig : public FunType > {}; template List operator()( const List& l ) const { if( null( tail( l ) ) ) return NIL; else return cons( head(l), curry( XInit(), tail(l) ) ); } }; #else struct XInit { template struct Sig : public FunType > {}; template OddList operator()( const L& l, Reuser1 > r = NIL ) const { if( null( tail( l ) ) ) return NIL; else return cons( head(l), r( XInit(), tail(l) ) ); } }; #endif } typedef Full1 Init; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Init init; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XLength { template struct Sig : public FunType {}; template size_t operator()( const L& ll ) const { List l = ll; size_t x = 0; while( !null(l) ) { l = tail(l); ++x; } return x; } }; } typedef Full1 Length; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Length length; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { // At is Haskell's operator (!!) struct XAt { template struct Sig : public FunType {}; template typename L::ElementType operator()( L l, size_t n ) const { while( n!=0 ) { l = tail(l); --n; } return head(l); } }; } typedef Full2 At; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN At at; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { #ifdef FCPP_SIMPLE_PRELUDE struct XFilter { template struct Sig : public FunType > {}; template List operator()( const P& p, const List& l ) const { if( null(l) ) return l; else if( p(head(l)) ) return cons( head(l), curry2( XFilter(), p, tail(l) ) ); else return XFilter()( p, tail(l) ); } }; #else template struct XFilterHelp : public Fun0Impl< OddList > { P p; mutable List l; XFilterHelp( const P& pp, const List& ll ) : p(pp), l(ll) {} OddList operator()() const { while(1) { if( null(l) ) return NIL; else if( p( head(l) ) ) { T x = head(l); l = tail(l); return cons( x, Fun0< OddList >(1,this) ); } else l = tail(l); } } }; struct XFilter { template struct Sig : public FunType > {}; template List operator()( const P& p, L l ) const { return Fun0< OddList >(1, new XFilterHelp(p,l) ); } }; /* For filter, the version with a Reuser is just not as good as the hand-coded reuse version, which is why this is commented out. struct XFilter { template struct Sig : public FunType > {}; template OddList operator()( const P& p, List l, Reuser2 > r = NIL ) const { while(1) { if( null(l) ) return NIL; else if( p(head(l)) ) return cons( head(l), r( XFilter(), p, tail(l) ) ); else r.iter( XFilter(), p, l = tail(l) ); } } }; */ #endif } typedef Full2 Filter; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Filter filter; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { #ifdef FCPP_SIMPLE_PRELUDE struct XConcat { template struct Sig : public FunType {}; template List operator()( const List >& l ) const { if( null(l) ) return List(); else return cat( head(l), curry(XConcat(),tail(l)) ); } }; #else struct XConcat { template struct Sig : public FunType > {}; template OddList operator()( const L& l, Reuser1 > r = NIL ) const { if( null(l) ) return NIL; else return cat( head(l), r(XConcat(),tail(l)) ); } }; #endif } typedef Full1 Concat; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Concat concat; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { // Note: this isn't lazy (even if 'op' is 'cons'). struct XFoldr { template struct Sig : public FunType {}; template E operator()( const Op& op, const E& e, const L& l ) const { if( null(l) ) return e; else return op( head(l), XFoldr()( op, e, tail(l) ) ); } }; } typedef Full3 Foldr; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Foldr foldr; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XFoldr1 { template struct Sig : public FunType {}; template typename L::ElementType operator()( const Op& op, const L& l ) const { return foldr( op, head(l), tail(l) ); } }; } typedef Full2 Foldr1; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Foldr1 foldr1; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XFoldl { template struct Sig : public FunType {}; template E operator()( const Op& op, E e, const L& ll ) const { List l = ll; while( !null(l) ) { E tmp( e ); e.~E(); new (&e) E( op(tmp,head(l)) ); l = tail(l); } return e; } }; } typedef Full3 Foldl; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Foldl foldl; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XFoldl1 { template struct Sig : public FunType {}; template typename L::ElementType operator()( const Op& op, const L& l ) const { return foldl( op, head(l), tail(l) ); } }; } typedef Full2 Foldl1; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Foldl1 foldl1; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XScanr { template struct Sig : public FunType > {}; template OddList operator()( const Op& op, const E& e, const L& l ) const { if( null(l) ) return cons( e, NIL ); else { OddList temp = XScanr()( op, e, tail(l) ); return cons( op( head(l), head(temp) ), temp ); } } }; } typedef Full3 Scanr; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Scanr scanr; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XScanr1 { template struct Sig : public FunType > {}; template OddList operator()( const Op& op, const L& l ) const { if( null( tail(l) ) ) return l.force(); else { OddList temp = XScanr1()( op, tail(l) ); return cons( op( head(l), head(temp) ), temp ); } } }; } typedef Full2 Scanr1; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Scanr1 scanr1; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { #ifdef FCPP_SIMPLE_PRELUDE struct XScanl { template struct Sig : public FunType > {}; template List operator()( const Op& op, const E& e, const List& l ) const { if( null(l) ) return cons( e, NIL ); else return cons( e, curry3( XScanl(), op, op(e,head(l)), tail(l) )); } }; #else struct XScanl { template struct Sig : public FunType > {}; template OddList operator()( const Op& op, const E& e, const L& l, Reuser3 > r = NIL ) const { if( null(l) ) return cons( e, NIL ); else return cons( e, r( XScanl(), op, op(e,head(l)), tail(l) ) ); } }; #endif } typedef Full3 Scanl; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Scanl scanl; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XScanl1 { template struct Sig : public FunType > {}; template OddList operator()( const Op& op, const L& l ) const { return scanl( op, head(l), tail(l) ); } }; } typedef Full2 Scanl1; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Scanl1 scanl1; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { #ifdef FCPP_SIMPLE_PRELUDE struct XIterate { template struct Sig : public FunType > {}; template List operator()( const F& f, const T& x ) const { return cons( x, curry2( XIterate(), f, f(x) ) ); } }; #else struct XIterate { template struct Sig : public FunType > {}; template OddList operator()( const F& f, const T& x, Reuser2 r = NIL ) const { return cons( x, r( XIterate(), f, f(x) ) ); } }; #endif } typedef Full2 Iterate; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Iterate iterate; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { #ifdef FCPP_SIMPLE_PRELUDE struct XRepeat { template struct Sig : public FunType > {}; template List operator()( const T& x ) const { return cons( x, curry( XRepeat(), x ) ); } }; #else struct XRepeat { template struct Sig : public FunType > {}; template OddList operator()( const T& x, Reuser1 r = NIL ) const { return cons( x, r( XRepeat(), x ) ); } }; #endif } typedef Full1 Repeat; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Repeat repeat; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { #ifdef FCPP_SIMPLE_PRELUDE struct XMap { template struct Sig : public FunType::ResultType> > {}; template List::ResultType> operator()( const F& f, const List& l ) const { if( null(l) ) return NIL; else return cons( f(head(l)), curry2( XMap(), f, tail(l) ) ); } }; #else struct XMap { template struct Sig : public FunType::ResultType> > {}; template OddList::ResultType> operator()( const F& f, const L& l, Reuser2 > r = NIL ) const { if( null(l) ) return NIL; else return cons( f(head(l)), r( XMap(), f, tail(l) ) ); } }; #endif } typedef Full2 Map; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Map map; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { #ifdef FCPP_SIMPLE_PRELUDE struct XTake { template struct Sig : public FunType > {}; template List operator()( size_t n, const List& l ) const { if( n==0 || null(l) ) return NIL; else return cons( head(l), curry2( XTake(), n-1, tail(l) ) ); } }; #else struct XTake { template struct Sig : public FunType > {}; template OddList operator()( size_t n, const L& l, Reuser2 > r = NIL ) const { if( n==0 || null(l) ) return NIL; else return cons( head(l), r( XTake(), n-1, tail(l) ) ); } }; #endif } typedef Full2 Take; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Take take; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XDrop { template struct Sig : public FunType > {}; template List operator()( size_t n, const L& ll ) const { List l = ll; while( n!=0 && !null(l) ) { --n; l = tail(l); } return l; } }; } typedef Full2 Drop; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Drop drop; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { #ifdef FCPP_SIMPLE_PRELUDE struct XTakeWhile { template struct Sig : public FunType > {}; template List operator()( const P& p, const List& l ) const { if( null(l) || !p( head(l) ) ) return NIL; else return cons( head(l), curry2( XTakeWhile(), p, tail(l) ) ); } }; #else struct XTakeWhile { template struct Sig : public FunType > {}; template OddList operator()( const P& p, const L& l, Reuser2 > r = NIL ) const { if( null(l) || !p( head(l) ) ) return NIL; else return cons( head(l), r( XTakeWhile(), p, tail(l) ) ); } }; #endif } typedef Full2 TakeWhile; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN TakeWhile takeWhile; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XDropWhile { template struct Sig : public FunType > {}; template List operator()( const P& p, const L& ll ) const { List l = ll; while( !null(l) && p( head(l) ) ) l = tail(l); return l; } }; } typedef Full2 DropWhile; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN DropWhile dropWhile; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XReplicate { template struct Sig : public FunType > {}; template OddList operator()( size_t n, const T& x ) const { return take( n, repeat(x) ); } }; } typedef Full2 Replicate; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Replicate replicate; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { #ifdef FCPP_SIMPLE_PRELUDE struct XCycle { template struct Sig : public FunType > {}; template List operator()( const List& l ) const { return cat( l, curry( XCycle(), l ) ); } }; #else struct XCycle { template struct Sig : public FunType > {}; template OddList operator()( const L& l, Reuser1 r = NIL ) const { return cat( l, r( XCycle(), l ) ); } }; #endif } typedef Full1 Cycle; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Cycle cycle; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XSplitAt { template struct Sig : public FunType,List > > {}; template std::pair,List > operator()( size_t n, const List& l ) const { if( n==0 || null(l) ) return std::make_pair( List(), l ); else { std::pair,List > temp = XSplitAt()( n-1, tail(l) ); List tl = cons( head(l), temp.first ); return std::make_pair( tl, temp.second ); } } }; } typedef Full2 SplitAt; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN SplitAt splitAt; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XSpan { template struct Sig : public FunType,List > > {}; template std::pair,List > operator()( const P& p, const List& l ) const { if( null(l) || !p(head(l)) ) return std::make_pair( List(), l ); else { std::pair,List > temp = XSpan()( p, tail(l) ); List tl = cons(head(l),temp.first); return std::make_pair( tl, temp.second ); } } }; } typedef Full2 Span; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Span span; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XBreak { template struct Sig : public FunType,List > > {}; template std::pair,List > operator()( const P& p, const List& l ) const { return span( Compose()( LogicalNot(), p ), l ); } }; } typedef Full2 Break; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Break break_; // C++ keyword, so add trailing underscore FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { template class XFlipHelper { Binary op; public: XFlipHelper( const Binary& b ) : op(b) {} template struct Sig : public FunType::ResultType > {}; template typename Binary::template Sig::ResultType operator()( const Y& y, const X& x ) const { return op( x, y ); } }; struct XFlip { template struct Sig : public FunType > > {}; template Full2 > operator()( const Binary& op ) const { return makeFull2( XFlipHelper( op ) ); } }; } typedef Full1 Flip; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Flip flip; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XReverse { template struct Sig : public FunType > {}; template List operator()( const List& l ) const { return curry3( foldl, flip(cons), List(), l ); } }; } typedef Full1 Reverse; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Reverse reverse; FCPP_MAYBE_NAMESPACE_CLOSE ////////////////////////////////////////////////////////////////////// // Not HSP but close ////////////////////////////////////////////////////////////////////// // These next two are defined as _lazy_ versions of these operators on lists namespace impl { struct XAnd : public CFunType,bool> { bool operator()( const List& l ) const { return null(dropWhile( equal(true), l )); } }; } typedef Full1 And; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN And and_; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XOr : public CFunType,bool> { bool operator()( const List& l ) const { return !null(dropWhile( equal(false), l )); } }; } typedef Full1 Or; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Or or_; FCPP_MAYBE_NAMESPACE_CLOSE ////////////////////////////////////////////////////////////////////// // Back to HSP ////////////////////////////////////////////////////////////////////// namespace impl { struct XAll { template struct Sig : public FunType {}; template bool operator()( const P& p, const L& l ) const { return and_( map( p, l ) ); } }; } typedef Full2 All; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN All all; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XAny { template struct Sig : public FunType {}; template bool operator()( const P& p, const L& l ) const { return or_( map( p, l ) ); } }; } typedef Full2 Any; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Any any; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XElem { template struct Sig : public FunType {}; template bool operator()( const T& x, const L& l ) const { return any( equal(x), l ); } }; } typedef Full2 Elem; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Elem elem; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XNotElem { template struct Sig : public FunType {}; template bool operator()( const T& x, const L& l ) const { return all( notEqual(x), l ); } }; } typedef Full2 NotElem; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN NotElem notElem; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XSum { template struct Sig : public FunType {}; template typename L::ElementType operator()( const L& l ) const { return foldl( plus, 0, l ); } }; } typedef Full1 Sum; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Sum sum; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XProduct { template struct Sig : public FunType {}; template typename L::ElementType operator()( const L& l ) const { return foldl( multiplies, 1, l ); } }; } typedef Full1 Product; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Product product; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XMinimum { template struct Sig : public FunType {}; template typename L::ElementType operator()( const L& l ) const { return foldl1( min, l ); } }; } typedef Full1 Minimum; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Minimum minimum; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XMaximum { template struct Sig : public FunType {}; template typename L::ElementType operator()( const L& l ) const { return foldl1( max, l ); } }; } typedef Full1 Maximum; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Maximum maximum; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { #ifdef FCPP_SIMPLE_PRELUDE struct XZipWith { template struct Sig : public FunType::ResultType> > {}; template List::ResultType> operator()( const Z& z, const List& a, const List& b) const { if( null(a) || null(b) ) return List::ResultType>(); else return cons( z(head(a),head(b)), curry3( XZipWith(), z, tail(a), tail(b) ) ); } }; #else struct XZipWith { template struct Sig : public FunType::ResultType> > {}; template OddList::ResultType> operator()( const Z& z, const LA& a, const LB& b, Reuser3, List > r = NIL ) const { if( null(a) || null(b) ) return NIL; else return cons( z(head(a),head(b)), r( XZipWith(), z, tail(a), tail(b) ) ); } }; #endif } typedef Full3 ZipWith; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN ZipWith zipWith; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XZip { template struct Sig : public FunType > > {}; template OddList > operator()( const LA& a, const LB& b ) const { return zipWith( MakePair(), a, b ); } }; } typedef Full2 Zip; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Zip zip; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XFst { template struct Sig : public FunType {}; template A operator()( const std::pair& p ) const { return p.first; } }; } typedef Full1 Fst; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Fst fst; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XSnd { template struct Sig : public FunType {}; template B operator()( const std::pair& p ) const { return p.second; } }; } typedef Full1 Snd; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Snd snd; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XUnzip { template struct Sig : public FunType, List > > {}; template std::pair< List, List > operator()( const LPT& l ) const { typedef typename LPT::ElementType::first_type F; typedef typename LPT::ElementType::second_type S; return std::make_pair( List(curry2(map,fst,l)), List(curry2(map,snd,l)) ); } }; } typedef Full1 Unzip; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Unzip unzip; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XGcdPrime { template struct Sig; template struct Sig : public FunType {}; template T operator()( T x, T y ) const { while( y!=0 ) { T tmp( x%y ); x = y; y = tmp; } return x; } }; struct XGcd { template struct Sig; template struct Sig : public FunType {}; template T operator()( const T& x, const T& y ) const { if( x==0 && y==0 ) throw fcpp_exception("Gcd error: x and y both 0"); return XGcdPrime()( x<0?-x:x, y<0?-y:y ); } }; } typedef Full2 Gcd; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Gcd gcd; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XOdd { template struct Sig : public FunType {}; template bool operator()( const T& x ) const { return x%2==1; } }; } typedef Full1 Odd; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Odd odd; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XEven { template struct Sig : public FunType {}; template bool operator()( const T& x ) const { return x%2==0; } }; } typedef Full1 Even; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Even even; FCPP_MAYBE_NAMESPACE_CLOSE ////////////////////////////////////////////////////////////////////// // Not HSP but close ////////////////////////////////////////////////////////////////////// // For some unknown reason, g++2.95.2 (for Solaris, at least) generates // poor code when these next two functoids are templates. (g++3 does // fine, regardless.) As a result, we make them just work with ints, // unless the user #defines the flag below. namespace impl { #ifdef FCPP_TEMPLATE_ENUM template struct XEFH : public Fun0Impl< OddList > { mutable T x; XEFH( const T& xx ) : x(xx) {} OddList operator()() const { ++x; return cons( x-1, Fun0 >(1,this) ); } }; struct XEnumFrom { template struct Sig : FunType > {}; template List operator()( const T& x ) const { return Fun0 >(1, new XEFH(x) ); } }; #else struct XEFH : public Fun0Impl< OddList > { mutable int x; XEFH( int xx ) : x(xx) {} OddList operator()() const { ++x; return cons( x-1, Fun0 >(1,this) ); } }; struct XEnumFrom : CFunType > { List operator()( int x ) const { return Fun0 >(1, new XEFH(x) ); } }; #endif } typedef Full1 EnumFrom; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN EnumFrom enumFrom; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { #ifdef FCPP_TEMPLATE_ENUM template struct XEFTH : public Fun0Impl > { mutable T x; T y; XEFTH( const T& xx, const T& yy ) : x(xx), y(yy) {} OddList operator()() const { if( x > y ) return NIL; ++x; return cons( x-1, Fun0 >( 1, this ) ); } }; struct XEnumFromTo { template struct Sig; template struct Sig : FunType > {}; template List operator()( const T& x, const T& y ) const { return Fun0 >( 1, new XEFTH(x,y) ); } }; #else struct XEFTH : public Fun0Impl > { mutable int x; int y; XEFTH( const int& xx, const int& yy ) : x(xx), y(yy) {} OddList operator()() const { if( x > y ) return NIL; ++x; return cons( x-1, Fun0 >( 1, this ) ); } }; struct XEnumFromTo : CFunType > { List operator()( const int& x, const int& y ) const { return Fun0 >( 1, new XEFTH(x,y) ); } }; #endif } typedef Full2 EnumFromTo; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN EnumFromTo enumFromTo; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { // Not HSP struct XListUntil { template struct Sig : public FunType > {}; template List operator()( const Pred& p, const Unary& f, const T& x ) const { return takeWhile( Compose()(logicalNot,p), iterate(f,x) ); } }; } typedef Full3 ListUntil; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN ListUntil listUntil; FCPP_MAYBE_NAMESPACE_CLOSE ////////////////////////////////////////////////////////////////////// // The "Maybe" type, from Haskell ////////////////////////////////////////////////////////////////////// struct AUniqueTypeForNothing {}; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN AUniqueTypeForNothing NOTHING; FCPP_MAYBE_NAMESPACE_CLOSE template class Maybe { OddList rep; public: typedef T ElementType; Maybe( AUniqueTypeForNothing ) {} Maybe() {} // the Nothing constructor Maybe( const T& x ) : rep( cons(x,NIL) ) {} // the Just constructor bool is_nothing() const { return null(rep); } T value() const { return head(rep); } }; namespace impl { struct XJust { template struct Sig : public FunType > {}; template typename Sig::ResultType operator()( const T& x ) const { return Maybe( x ); } }; } typedef Full1 Just; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Just just; FCPP_MAYBE_NAMESPACE_CLOSE // Haskell's "()" type/value struct Empty {}; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Empty empty; FCPP_MAYBE_NAMESPACE_CLOSE // Haskell has curry() and uncurry() for pairs; we call these hCurry() // and hUncurry(). namespace impl { struct XHCurry { template struct Sig : public FunType >::ResultType> {}; template typename Sig::ResultType operator()( const F& f, const X& x, const Y& y ) const { return f( makePair(x,y) ); } }; } typedef Full3 HCurry; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN HCurry hCurry; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { struct XHUncurry { template struct Sig : public FunType::ResultType> {}; template typename Sig::ResultType operator()( const F& f, const P& p ) const { return f( fst(p), snd(p) ); } }; } typedef Full2 HUncurry; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN HUncurry hUncurry; FCPP_MAYBE_NAMESPACE_CLOSE // That's the end of the Haskell stuff; on to made-just-for-FC++ ////////////////////////////////////////////////////////////////////// // Useful effect combinators ////////////////////////////////////////////////////////////////////// // Here we define some combinators for statement sequencing: // before(f,g)(args) = { f(); return g(args); } // after(f,g)(args) = { r = f(args); g(); return r; } // That is, before() prepends a thunk onto a functoid, and after() // appends the thunk onto the back of a functoid. Finally, noOp // results in a thunk that does nothing, and serves as the left/right // identity element for before/after thusly: // f = before( noOp, f ) = after( f, noOp ) // Note: the effect happens when all of the functoid's expected // arguments finally arrive (which, thanks to currying, might not be at // the "next call". So if g() expects two arguments, note that // before( f, g )( x ) // will not call f() now, rather it waits for another argument. namespace impl { struct XNoOp : public CFunType { void operator()() const {} }; } typedef Full0 NoOp; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN NoOp noOp; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { template class XBeforer0 : public CFunType::ResultType> { F f; G g; public: XBeforer0( const F& ff, const G& gg ) : f(ff), g(gg) {} typename RT::ResultType operator()() const { f(); return g(); } }; template class XBeforer1 { F f; G g; public: XBeforer1( const F& ff, const G& gg ) : f(ff), g(gg) {} template struct Sig : public FunType::Arg1Type,typename RT::ResultType> {}; template typename Sig::ResultType operator()( const X& x ) const { f(); return g(x); } }; template class XBeforer2 { F f; G g; public: XBeforer2( const F& ff, const G& gg ) : f(ff), g(gg) {} template struct Sig : public FunType::Arg1Type, typename RT::Arg2Type, typename RT::ResultType> {}; template typename Sig::ResultType operator()( const X& x, const Y& y ) const { f(); return g(x,y); } }; template class XBeforer3 { F f; G g; public: XBeforer3( const F& ff, const G& gg ) : f(ff), g(gg) {} template struct Sig : public FunType::Arg1Type, typename RT::Arg2Type, typename RT::Arg3Type, typename RT::ResultType> {}; template typename Sig::ResultType operator()( const X& x, const Y& y, const Z& z ) const { f(); return g(x,y,z); } }; class XBefore { template struct Helper; template struct Helper<0,F,G> { typedef Full0 > Result; static Result go( const F& f, const G& g ) { return makeFull0( XBeforer0(f,g) ); } }; template struct Helper<1,F,G> { typedef Full1 > Result; static Result go( const F& f, const G& g ) { return makeFull1( XBeforer1(f,g) ); } }; template struct Helper<2,F,G> { typedef Full2 > Result; static Result go( const F& f, const G& g ) { return makeFull2( XBeforer2(f,g) ); } }; template struct Helper<3,F,G> { typedef Full3 > Result; static Result go( const F& f, const G& g ) { return makeFull3( XBeforer3(f,g) ); } }; public: template struct Sig : public FunType::max_args,F,G>::Result> {}; template typename Sig::ResultType operator()( const F& f, const G& g ) const { return Helper::max_args,F,G>::go( f, g ); } }; } typedef Full2 Before; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Before before; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { template class XAfterer0 : public CFunType::ResultType> { F f; G g; public: XAfterer0( const F& ff, const G& gg ) : f(ff), g(gg) {} typename RT::ResultType operator()() const { typename RT::ResultType tmp = f(); g(); return tmp; } }; template class XAfterer1 { F f; G g; public: XAfterer1( const F& ff, const G& gg ) : f(ff), g(gg) {} template struct Sig : public FunType::Arg1Type, typename RT::ResultType> {}; template typename Sig::ResultType operator()( const X& x ) const { typename Sig::ResultType tmp = f(x); g(); return tmp; } }; template class XAfterer2 { F f; G g; public: XAfterer2( const F& ff, const G& gg ) : f(ff), g(gg) {} template struct Sig : public FunType::Arg1Type, typename RT::Arg2Type, typename RT::ResultType> {}; template typename Sig::ResultType operator()( const X& x, const Y& y ) const { typename Sig::ResultType tmp = f(x,y); g(); return tmp; } }; template class XAfterer3 { F f; G g; public: XAfterer3( const F& ff, const G& gg ) : f(ff), g(gg) {} template struct Sig : public FunType::Arg1Type, typename RT::Arg2Type, typename RT::Arg3Type, typename RT::ResultType> {}; template typename Sig::ResultType operator()( const X& x, const Y& y, const Z& z ) const { typename Sig::ResultType tmp = f(x,y,z); g(); return tmp; } }; class XAfter { template struct Helper; template struct Helper<0,F,G> { typedef Full0 > Result; static Result go( const F& f, const G& g ) { return makeFull0( XAfterer0(f,g) ); } }; template struct Helper<1,F,G> { typedef Full1 > Result; static Result go( const F& f, const G& g ) { return makeFull1( XAfterer1(f,g) ); } }; template struct Helper<2,F,G> { typedef Full2 > Result; static Result go( const F& f, const G& g ) { return makeFull2( XAfterer2(f,g) ); } }; template struct Helper<3,F,G> { typedef Full3 > Result; static Result go( const F& f, const G& g ) { return makeFull3( XAfterer3(f,g) ); } }; public: template struct Sig : public FunType::max_args,F,G>::Result> {}; template typename Sig::ResultType operator()( const F& f, const G& g ) const { return Helper::max_args,F,G>::go( f, g ); } }; } typedef Full2 After; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN After after; FCPP_MAYBE_NAMESPACE_CLOSE // emptify(f)(yadda) == f(yadda), but throws away f's result (even if // it's void) and returns Empty instead. This is useful because // length( map( emptify(effectFunctoid), someList ) ) // is an easy way to do something with each element of someList. namespace impl { template class XEmptifier0 : public CFunType { F f; public: XEmptifier0( const F& ff ) : f(ff) {} Empty operator()() const { f(); return Empty(); } }; template class XEmptifier1 { F f; public: XEmptifier1( const F& ff ) : f(ff) {} template struct Sig : public FunType::Arg1Type,Empty> {}; template typename Sig::ResultType operator()( const X& x ) const { f(x); return Empty(); } }; template class XEmptifier2 { F f; public: XEmptifier2( const F& ff ) : f(ff) {} template struct Sig : public FunType::Arg1Type, typename RT::Arg2Type, Empty> {}; template typename Sig::ResultType operator()( const X& x, const Y& y ) const { f(x,y); return Empty(); } }; template class XEmptifier3 { F f; public: XEmptifier3( const F& ff ) : f(ff) {} template struct Sig : public FunType::Arg1Type, typename RT::Arg2Type, typename RT::Arg3Type, Empty> {}; template typename Sig::ResultType operator()( const X& x, const Y& y, const Z& z ) const { f(x,y,z); return Empty(); } }; class XEmptify { template struct Helper; template struct Helper<0,F> { typedef Full0 > Result; static Result go( const F& f ) { return makeFull0( XEmptifier0(f) ); } }; template struct Helper<1,F> { typedef Full1 > Result; static Result go( const F& f ) { return makeFull1( XEmptifier1(f) ); } }; template struct Helper<2,F> { typedef Full2 > Result; static Result go( const F& f ) { return makeFull2( XEmptifier2(f) ); } }; template struct Helper<3,F> { typedef Full3 > Result; static Result go( const F& f ) { return makeFull3( XEmptifier3(f) ); } }; public: template struct Sig : public FunType::max_args,F>::Result> {}; template typename Sig::ResultType operator()( const F& f ) const { return Helper::max_args,F>::go( f ); } }; } typedef Full1 Emptify; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Emptify emptify; FCPP_MAYBE_NAMESPACE_CLOSE #ifndef FCPP_I_AM_GCC2 namespace impl { struct XThunkFuncToFunc { // tftf(f)(yadda) = f()(yadda) // f is a thunk that returns a functoid; this combinator 'hides' the thunk. // can be useful to break what would otherwise be infinite recursion. template class TFTFH0 : CFunType::ResultType>::ResultType> { F f; public: TFTFH0( const F& ff ) : f(ff) {} template typename RT::ResultType>::ResultType operator()() const { return f()(); } }; template class TFTFH1 { F f; public: TFTFH1( const F& ff ) : f(ff) {} template struct Sig : public FunType< typename RT::ResultType,X>::Arg1Type, typename RT::ResultType,X>::ResultType > {}; template typename Sig::ResultType operator()( const X& x ) const { return f()( x ); } }; template class TFTFH2 { F f; public: TFTFH2( const F& ff ) : f(ff) {} template struct Sig : public FunType< typename RT::ResultType,X,Y>::Arg1Type, typename RT::ResultType,X,Y>::Arg2Type, typename RT::ResultType,X,Y>::ResultType > {}; template typename Sig::ResultType operator()( const X& x, const Y& y ) const { return f()( x, y ); } }; template class TFTFH3 { F f; public: TFTFH3( const F& ff ) : f(ff) {} template struct Sig : public FunType< typename RT::ResultType,X,Y,Z>::Arg1Type, typename RT::ResultType,X,Y,Z>::Arg2Type, typename RT::ResultType,X,Y,Z>::Arg3Type, typename RT::ResultType,X,Y,Z>::ResultType > {}; template typename Sig::ResultType operator()( const X& x, const Y& y, const Z& z ) const { return f()( x, y, z ); } }; template struct Helper; template struct Helper<0,F> { typedef Full0 > Result; static Result go( const F& f ) { return makeFull0( TFTFH0(f) ); } }; template struct Helper<1,F> { typedef Full1 > Result; static Result go( const F& f ) { return makeFull1( TFTFH1(f) ); } }; template struct Helper<2,F> { typedef Full2 > Result; static Result go( const F& f ) { return makeFull2( TFTFH2(f) ); } }; template struct Helper<3,F> { typedef Full3 > Result; static Result go( const F& f ) { return makeFull3( TFTFH3(f) ); } }; template struct Sig : public FunType::ResultType>::max_args,F>::Result> {}; template typename Sig::ResultType operator()( const F& f ) const { return Helper::ResultType> ::max_args,F>::go(f); } }; } typedef Full1 ThunkFuncToFunc; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN ThunkFuncToFunc thunkFuncToFunc; FCPP_MAYBE_NAMESPACE_CLOSE #endif ////////////////////////////////////////////////////////////////////// // uncurry ////////////////////////////////////////////////////////////////////// // Sometimes FC++ expressions result in functoids where, for example, // f(x)(y) // is legal but // f(x,y) // is not, owing to the fact that (in the example) f() is a one-argument // functoid the returns another one-argument functoid, which is // different from a two-argument functoid. (In Haskell, the two types // are identical.) uncurry() wraps a functoid in a magical cloak which // splits up its arguments, so that, for example, // uncurry(f)(x,y,z) = f(x)(y)(z) // It rarely arises that you need this, but when you do, you can't live // without it. // // FIX THIS: Note that uncurry() (as well as curryN()) means something // different in FC++ than what it does in Haskell. namespace impl { template class XUncurryable : public SmartFunctoid3 { F f; public: XUncurryable( const F& ff ) : f(ff) { FunctoidTraits::template ensure_accepts<1>::args(); } template struct Sig : public FunType::Arg1Type, typename RT::ResultType,Y>::Arg1Type, typename RT::ResultType,Y>::ResultType,Z> ::Arg1Type, typename RT::ResultType,Y>::ResultType,Z> ::ResultType> {}; template struct Sig : public FunType::Arg1Type, typename RT::ResultType,Y>::Arg1Type, typename RT::ResultType,Y>::ResultType> {}; template struct Sig : public FunType::Arg1Type, typename RT::ResultType> {}; template typename Sig::ResultType operator()( const X& x, const Y& y, const Z& z ) const { return f(x)(y)(z); } template typename Sig::ResultType operator()( const X& x, const Y& y ) const { return f(x)(y); } template typename Sig::ResultType operator()( const X& x ) const { return f(x); } #ifdef FCPP_ENABLE_LAMBDA typedef XUncurryable This; template typename fcpp_lambda::BracketCallable::Result operator[]( const A& a ) const { return fcpp_lambda::BracketCallable::go( *this, a ); } #endif }; struct XUncurry { template struct Sig : FunType > {}; template XUncurryable operator()( const F& f ) const { return XUncurryable(f); } }; } typedef Full1 Uncurry; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Uncurry uncurry; FCPP_MAYBE_NAMESPACE_CLOSE // Uncurry0 is truly a different case from uncurry: // uncurry0(f)(x,y,z) = f()(x)(y)(z) namespace impl { template class XUncurryable0 { F f; public: XUncurryable0( const F& ff ) : f(ff) { FunctoidTraits::template ensure_accepts<0>::args(); } template struct Sig : public FunType::ResultType,X>::Arg1Type, typename RT::ResultType,X>::ResultType> {}; template typename Sig::ResultType operator()( const X& x ) const { return f()(x); } }; struct XUncurry0 { template struct Sig : FunType > > {}; template XUncurryable > operator()( const F& f ) const { return ::fcpp::uncurry( XUncurryable0(f) ); } }; } typedef Full1 Uncurry0; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Uncurry0 uncurry0; FCPP_MAYBE_NAMESPACE_CLOSE ////////////////////////////////////////////////////////////////////// // duplicate() and ignore() ////////////////////////////////////////////////////////////////////// // duplicate() duplicates the first argument of a functoid, whereas // ignore() ignores it: // duplicate(f)(x) = f(x)(x) // ignore(f)(x)(args) = f(args) namespace impl { template class XDuplicater { F f; public: XDuplicater( const F& ff ) : f(ff) {} template struct Sig : public FunType::ResultType, X>::ResultType> {}; template typename Sig::ResultType operator()( const X& x ) const { return f(x)(x); } }; struct XDuplicate { template struct Sig : public FunType > > {}; template Full1 > operator()( const F& f ) const { return makeFull1( XDuplicater(f) ); } }; } typedef Full1 Duplicate; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Duplicate duplicate; FCPP_MAYBE_NAMESPACE_CLOSE namespace impl { template class XIgnorer1 { F f; public: XIgnorer1( const F& ff ) : f(ff) {} template struct Sig : public FunType::ResultType> {}; template typename Sig::ResultType operator()( const X& ) const { return f(); } }; template class XIgnorer2 { F f; public: XIgnorer2( const F& ff ) : f(ff) {} template struct Sig : public FunType::Arg1Type,typename RT::ResultType> {}; template typename Sig::ResultType operator()( const X&, const Y& y ) const { return f(y); } }; template class XIgnorer3 { F f; public: XIgnorer3( const F& ff ) : f(ff) {} template struct Sig : public FunType::Arg1Type, typename RT::Arg2Type, typename RT::ResultType> {}; template typename Sig::ResultType operator()( const X&, const Y& y, const Z& z ) const { return f(y,z); } }; class XIgnore { template struct Helper; template struct Helper<0,F> { typedef Full1< XIgnorer1 > Result; static inline Result go( const F& f ) { return makeFull1( XIgnorer1(f) ); } }; template struct Helper<1,F> { typedef Full2< XIgnorer2 > Result; static inline Result go( const F& f ) { return makeFull2( XIgnorer2(f) ); } }; template struct Helper<2,F> { typedef Full3< XIgnorer3 > Result; static inline Result go( const F& f ) { return makeFull3( XIgnorer3(f) ); } }; public: template struct Sig : public FunType::max_args,F>::Result> {}; template typename Sig::ResultType operator()( const F& f ) const { return Helper::max_args,F>::go(f); } }; } typedef Full1 Ignore; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Ignore ignore; FCPP_MAYBE_NAMESPACE_CLOSE ////////////////////////////////////////////////////////////////////// // ConstructN ////////////////////////////////////////////////////////////////////// // C++ constructors are not functions, and thus cannot easily be turned // into functoids. So we write these helpers. For example, // construct2()(x,y) = Foo(x,y) // Foo is a type name // Note also that construct1 also serves the role of an explicit // converter; if Foos (or any type) can be converted into Bars, then we // could use a construct1 functoid to capture the conversion function: // construct1() // functoid that converts arg into a Bar // construct1()(x) = Bar(x) // Note also that these are template functions returning full functoids, // and we have template structs which name the types of the functoids. namespace impl { template struct XConstruct0 : public CFunType { T operator()() const { return T(); } }; } template Full0 > construct0() { return makeFull0( impl::XConstruct0() ); } template struct Construct0 { typedef Full0 > Type; }; namespace impl { template struct XConstruct1 { template struct Sig : FunType {}; template T operator()( const X& x ) const { return T(x); } }; } template Full1 > construct1() { return makeFull1( impl::XConstruct1() ); } template struct Construct1 { typedef Full1 > Type; }; namespace impl { template struct XConstruct2 { template struct Sig : FunType {}; template T operator()( const X& x, const Y& y ) const { return T(x,y); } }; } template Full2 > construct2() { return makeFull2( impl::XConstruct2() ); } template struct Construct2 { typedef Full2 > Type; }; namespace impl { template struct XConstruct3 { template struct Sig : FunType {}; template T operator()( const X& x, const Y& y, const Z& z ) const { return T(x,y,z); } }; } template Full3 > construct3() { return makeFull3( impl::XConstruct3() ); } template struct Construct3 { typedef Full3 > Type; }; ////////////////////////////////////////////////////////////////////// // NewN works like ConstructN but "new"s it and returns the ptr ////////////////////////////////////////////////////////////////////// namespace impl { template struct XNew0 : public CFunType { T* operator()() const { return new T(); } }; } template Full0 > new0() { return makeFull0( impl::XNew0() ); } template struct New0 { typedef Full0 > Type; }; namespace impl { template struct XNew1 { template struct Sig : FunType {}; template T* operator()( const X& x ) const { return new T(x); } }; } template Full1 > new1() { return makeFull1( impl::XNew1() ); } template struct New1 { typedef Full1 > Type; }; namespace impl { template struct XNew2 { template struct Sig : FunType {}; template T* operator()( const X& x, const Y& y ) const { return new T(x,y); } }; } template Full2 > new2() { return makeFull2( impl::XNew2() ); } template struct New2 { typedef Full2 > Type; }; namespace impl { template struct XNew3 { template struct Sig : FunType {}; template T* operator()( const X& x, const Y& y, const Z& z ) const { return new T(x,y,z); } }; } template Full3 > new3() { return makeFull3( impl::XNew3() ); } template struct New3 { typedef Full3 > Type; }; } // end namespace fcpp #ifdef FCPP_ENABLE_LAMBDA #include "monad.h" #endif #endif