// // Copyright (c) 2000,2001,2002 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 { struct Id { template struct Sig : public FunType {}; template T operator()( const T& x ) const { return x; } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Id id; FCPP_MAYBE_NAMESPACE_CLOSE // Plain "compose" makes Compose0 no longer necessary, but g++2.95.2 has // bugs that prevent compose() from working on 0-arg functoids, so we // keep this around for now. Consider Compose0 deprecated. template class Compose0Helper : public CFunType< typename F::template Sig::ResultType>::ResultType> { F f; G g; public: Compose0Helper( const F& a, const G& b ) : f(a), g(b) {} typename F::template Sig::ResultType>::ResultType operator()() const { return f( g() ); } }; struct Compose0 { template struct Sig : public FunType > {}; template Compose0Helper operator()( const F& f, const G& g ) const { return Compose0Helper( f, g ); } }; template class ComposerBase { protected: F f; G g; ComposerBase( const F& ff, const G& gg ) : f(ff), g(gg) {} }; template class ComposerMixin : public CallableWithoutArguments, public ComposerBase { protected: using ComposerBase::f; using ComposerBase::g; ComposerMixin( const F& ff, const G& gg ) : ComposerBase(ff,gg) {} public: typename RT::ResultType>::ResultType operator()() const { return f( g() ); } }; template class ComposerMixin : public ComposerBase { protected: using ComposerBase::f; using ComposerBase::g; ComposerMixin( const F& ff, const G& gg ) : ComposerBase(ff,gg) {} template struct Impossible {}; public: template void operator()( Impossible& ) {} }; template class Composer : public ComposerMixin::value> { typedef ComposerMixin::value> Super; using Super::f; using Super::g; public: #ifndef FCPP_NO_USING_DECLS using Super::operator(); #endif Composer( const F& ff, const G& gg ) : Super(ff,gg) {} template struct Sig : FunType::Arg1Type, typename RT::Arg2Type, typename RT::Arg3Type, typename RT::ResultType>::ResultType> {}; template struct Sig : FunType::Arg1Type, typename RT::Arg2Type, typename RT::ResultType>::ResultType> {}; template struct Sig : FunType::Arg1Type, typename RT::ResultType>::ResultType> {}; template struct Sig : FunType< typename RT::ResultType>::ResultType> {}; template typename Sig::ResultType operator()( const X& x ) const { return f( g(x) ); } template typename Sig::ResultType operator()( const X& x, const Y& y ) const { return f( g(x,y) ); } 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 (.) for f.g where g is a one-arg struct Compose { template struct Sig : public FunType > {}; template Composer operator()( const F& f, const G& g ) const { return Composer( f, g ); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Compose compose_; FCPP_MAYBE_EXTERN Curryable2 compose FCPP_MAYBE_INIT((compose_)); FCPP_MAYBE_NAMESPACE_CLOSE template class Compose2Helper { F f; G g; H h; public: Compose2Helper( 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 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 struct Compose2 { template struct Sig : public FunType > {}; template Compose2Helper operator()(const F& f, const G& g, const H& h) const { return Compose2Helper( f, g, h ); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Compose2 _compose2; FCPP_MAYBE_EXTERN Curryable3 compose2 FCPP_MAYBE_INIT((_compose2)); FCPP_MAYBE_NAMESPACE_CLOSE struct Until { 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; } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Until _until; FCPP_MAYBE_EXTERN Curryable3 until FCPP_MAYBE_INIT((_until)); FCPP_MAYBE_NAMESPACE_CLOSE struct Last { 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); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Last last; FCPP_MAYBE_NAMESPACE_CLOSE #ifdef FCPP_SIMPLE_PRELUDE struct Init { template struct Sig : public FunType > {}; template List operator()( const List& l ) const { if( null( tail( l ) ) ) return NIL; else return cons( head(l), curry( Init(), tail(l) ) ); } }; #else struct Init { 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( Init(), tail(l) ) ); } }; #endif FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Init init; FCPP_MAYBE_NAMESPACE_CLOSE struct Length { 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; } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Length length; FCPP_MAYBE_NAMESPACE_CLOSE // At is Haskell's operator (!!) struct At { 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); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN At _at; FCPP_MAYBE_EXTERN Curryable2 at FCPP_MAYBE_INIT((_at)); FCPP_MAYBE_NAMESPACE_CLOSE #ifdef FCPP_SIMPLE_PRELUDE struct Filter { 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( Filter(), p, tail(l) ) ); else return Filter()( p, tail(l) ); } }; #else template struct FilterHelp : public Fun0Impl< OddList > { P p; mutable List l; FilterHelp( 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 Filter { template struct Sig : public FunType > {}; template List operator()( const P& p, L l ) const { return Fun0< OddList >(1, new FilterHelp(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 Filter { 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( Filter(), p, tail(l) ) ); else r.iter( Filter(), p, l = tail(l) ); } } }; */ #endif FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Filter _filter; FCPP_MAYBE_EXTERN Curryable2 filter FCPP_MAYBE_INIT((_filter)); FCPP_MAYBE_NAMESPACE_CLOSE #ifdef FCPP_SIMPLE_PRELUDE struct Concat { template struct Sig : public FunType {}; template List operator()( const List >& l ) const { if( null(l) ) return List(); else return cat( head(l), curry(Concat(),tail(l)) ); } }; #else struct Concat { 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(Concat(),tail(l)) ); } }; #endif FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Concat concat; FCPP_MAYBE_NAMESPACE_CLOSE // Note: this isn't lazy (even if 'op' is 'cons'). struct Foldr { 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), Foldr()( op, e, tail(l) ) ); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Foldr _foldr; FCPP_MAYBE_EXTERN Curryable3 foldr FCPP_MAYBE_INIT((_foldr)); FCPP_MAYBE_NAMESPACE_CLOSE struct Foldr1 { template struct Sig : public FunType {}; template typename L::ElementType operator()( const Op& op, const L& l ) const { return foldr( op, head(l), tail(l) ); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Foldr1 _foldr1; FCPP_MAYBE_EXTERN Curryable2 foldr1 FCPP_MAYBE_INIT((_foldr1)); FCPP_MAYBE_NAMESPACE_CLOSE struct Foldl { 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; } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Foldl _foldl; FCPP_MAYBE_EXTERN Curryable3 foldl FCPP_MAYBE_INIT((_foldl)); FCPP_MAYBE_NAMESPACE_CLOSE struct Foldl1 { template struct Sig : public FunType {}; template typename L::ElementType operator()( const Op& op, const L& l ) const { return foldl( op, head(l), tail(l) ); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Foldl1 _foldl1; FCPP_MAYBE_EXTERN Curryable2 foldl1 FCPP_MAYBE_INIT((_foldl1)); FCPP_MAYBE_NAMESPACE_CLOSE struct Scanr { 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 = Scanr()( op, e, tail(l) ); return cons( op( head(l), head(temp) ), temp ); } } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Scanr _scanr; FCPP_MAYBE_EXTERN Curryable3 scanr FCPP_MAYBE_INIT((_scanr)); FCPP_MAYBE_NAMESPACE_CLOSE struct Scanr1 { template struct Sig : public FunType > {}; template OddList operator()( const Op& op, const L& l ) const { if( null( tail(l) ) ) return l; else { OddList temp = Scanr1()( op, tail(l) ); return cons( op( head(l), head(temp) ), temp ); } } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Scanr1 _scanr1; FCPP_MAYBE_EXTERN Curryable2 scanr1 FCPP_MAYBE_INIT((_scanr1)); FCPP_MAYBE_NAMESPACE_CLOSE #ifdef FCPP_SIMPLE_PRELUDE struct Scanl { 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( Scanl(), op, op(e,head(l)), tail(l) )); } }; #else struct Scanl { 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( Scanl(), op, op(e,head(l)), tail(l) ) ); } }; #endif FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Scanl _scanl; FCPP_MAYBE_EXTERN Curryable3 scanl FCPP_MAYBE_INIT((_scanl)); FCPP_MAYBE_NAMESPACE_CLOSE struct Scanl1 { template struct Sig : public FunType > {}; template OddList operator()( const Op& op, const L& l ) const { return scanl( op, head(l), tail(l) ); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Scanl1 _scanl1; FCPP_MAYBE_EXTERN Curryable2 scanl1 FCPP_MAYBE_INIT((_scanl1)); FCPP_MAYBE_NAMESPACE_CLOSE #ifdef FCPP_SIMPLE_PRELUDE struct Iterate { template struct Sig : public FunType > {}; template List operator()( const F& f, const T& x ) const { return cons( x, curry2( Iterate(), f, f(x) ) ); } }; #else struct Iterate { template struct Sig : public FunType > {}; template OddList operator()( const F& f, const T& x, Reuser2 r = NIL ) const { return cons( x, r( Iterate(), f, f(x) ) ); } }; #endif FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Iterate _iterate; FCPP_MAYBE_EXTERN Curryable2 iterate FCPP_MAYBE_INIT((_iterate)); FCPP_MAYBE_NAMESPACE_CLOSE #ifdef FCPP_SIMPLE_PRELUDE struct Repeat { template struct Sig : public FunType > {}; template List operator()( const T& x ) const { return cons( x, curry( Repeat(), x ) ); } }; #else struct Repeat { template struct Sig : public FunType > {}; template OddList operator()( const T& x, Reuser1 r = NIL ) const { return cons( x, r( Repeat(), x ) ); } }; #endif FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Repeat repeat; FCPP_MAYBE_NAMESPACE_CLOSE #ifdef FCPP_SIMPLE_PRELUDE struct Map { 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( Map(), f, tail(l) ) ); } }; #else struct Map { 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( Map(), f, tail(l) ) ); } }; #endif FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Map _map; FCPP_MAYBE_EXTERN Curryable2 map FCPP_MAYBE_INIT((_map)); FCPP_MAYBE_NAMESPACE_CLOSE #ifdef FCPP_SIMPLE_PRELUDE struct Take { 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( Take(), n-1, tail(l) ) ); } }; #else struct Take { 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( Take(), n-1, tail(l) ) ); } }; #endif FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Take _take; FCPP_MAYBE_EXTERN Curryable2 take FCPP_MAYBE_INIT((_take)); FCPP_MAYBE_NAMESPACE_CLOSE struct Drop { 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; } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Drop _drop; FCPP_MAYBE_EXTERN Curryable2 drop FCPP_MAYBE_INIT((_drop)); FCPP_MAYBE_NAMESPACE_CLOSE #ifdef FCPP_SIMPLE_PRELUDE struct TakeWhile { 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( TakeWhile(), p, tail(l) ) ); } }; #else struct TakeWhile { 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( TakeWhile(), p, tail(l) ) ); } }; #endif FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN TakeWhile _takeWhile; FCPP_MAYBE_EXTERN Curryable2 takeWhile FCPP_MAYBE_INIT((_takeWhile)); FCPP_MAYBE_NAMESPACE_CLOSE struct DropWhile { 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; } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN DropWhile _dropWhile; FCPP_MAYBE_EXTERN Curryable2 dropWhile FCPP_MAYBE_INIT((_dropWhile)); FCPP_MAYBE_NAMESPACE_CLOSE struct Replicate { template struct Sig : public FunType > {}; template OddList operator()( size_t n, const T& x ) const { return take( n, repeat(x) ); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Replicate _replicate; FCPP_MAYBE_EXTERN Curryable2 replicate FCPP_MAYBE_INIT((_replicate)); FCPP_MAYBE_NAMESPACE_CLOSE #ifdef FCPP_SIMPLE_PRELUDE struct Cycle { template struct Sig : public FunType > {}; template List operator()( const List& l ) const { return cat( l, curry( Cycle(), l ) ); } }; #else struct Cycle { template struct Sig : public FunType > {}; template OddList operator()( const L& l, Reuser1 r = NIL ) const { return cat( l, r( Cycle(), l ) ); } }; #endif FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Cycle cycle; FCPP_MAYBE_NAMESPACE_CLOSE struct SplitAt { 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 = SplitAt()( n-1, tail(l) ); List tl = cons( head(l), temp.first ); return std::make_pair( tl, temp.second ); } } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN SplitAt _splitAt; FCPP_MAYBE_EXTERN Curryable2 splitAt FCPP_MAYBE_INIT((_splitAt)); FCPP_MAYBE_NAMESPACE_CLOSE struct Span { 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 = Span()( p, tail(l) ); List tl = cons(head(l),temp.first); return std::make_pair( tl, temp.second ); } } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Span _span; FCPP_MAYBE_EXTERN Curryable2 span FCPP_MAYBE_INIT((_span)); FCPP_MAYBE_NAMESPACE_CLOSE struct Break { template struct Sig : public FunType,List > > {}; template std::pair,List > operator()( const P& p, const List& l ) const { return span( Compose()( LogicalNot(), p ), l ); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Break _break_; FCPP_MAYBE_EXTERN Curryable2 break_ FCPP_MAYBE_INIT((_break_)); // C++ keyword, so add trailing underscore FCPP_MAYBE_NAMESPACE_CLOSE template class FlipHelper { Binary op; public: FlipHelper( 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 Flip { template struct Sig : public FunType > > {}; template Curryable2 > operator()( const Binary& op ) const { return Curryable2 >( FlipHelper( op ) ); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Flip flip; FCPP_MAYBE_NAMESPACE_CLOSE struct Reverse { template struct Sig : public FunType > {}; template List operator()( const List& l ) const { return curry3( foldl, flip(cons), List(), l ); } }; 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 struct And : public CFunType,bool> { bool operator()( const List& l ) const { return null(dropWhile( curry2(Equal(),true), l )); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN And and_; FCPP_MAYBE_NAMESPACE_CLOSE struct Or : public CFunType,bool> { bool operator()( const List& l ) const { return !null(dropWhile( curry2(Equal(),false), l )); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Or or_; FCPP_MAYBE_NAMESPACE_CLOSE ////////////////////////////////////////////////////////////////////// // Back to HSP ////////////////////////////////////////////////////////////////////// struct All { template struct Sig : public FunType {}; template bool operator()( const P& p, const L& l ) const { return And()( map( p, l ) ); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN All _all; FCPP_MAYBE_EXTERN Curryable2 all FCPP_MAYBE_INIT((_all)); FCPP_MAYBE_NAMESPACE_CLOSE struct Any { template struct Sig : public FunType {}; template bool operator()( const P& p, const L& l ) const { return Or()( map( p, l ) ); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Any _any; FCPP_MAYBE_EXTERN Curryable2 any FCPP_MAYBE_INIT((_any)); FCPP_MAYBE_NAMESPACE_CLOSE struct Elem { template struct Sig : public FunType {}; template bool operator()( const T& x, const L& l ) const { return any( bind2of2( Equal(), x ), l ); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Elem _elem; FCPP_MAYBE_EXTERN Curryable2 elem FCPP_MAYBE_INIT((_elem)); FCPP_MAYBE_NAMESPACE_CLOSE struct NotElem { template struct Sig : public FunType {}; template bool operator()( const T& x, const L& l ) const { return all( bind2of2( NotEqual(), x ), l ); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN NotElem _notElem; FCPP_MAYBE_EXTERN Curryable2 notElem FCPP_MAYBE_INIT((_notElem)); FCPP_MAYBE_NAMESPACE_CLOSE struct Sum { template struct Sig : public FunType {}; template typename L::ElementType operator()( const L& l ) const { return foldl( Plus(), 0, l ); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Sum sum; FCPP_MAYBE_NAMESPACE_CLOSE struct Product { template struct Sig : public FunType {}; template typename L::ElementType operator()( const L& l ) const { return foldl( Multiplies(), 1, l ); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Product product; FCPP_MAYBE_NAMESPACE_CLOSE struct Minimum { template struct Sig : public FunType {}; template typename L::ElementType operator()( const L& l ) const { return foldl1( Min(), l ); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Minimum minimum; FCPP_MAYBE_NAMESPACE_CLOSE struct Maximum { template struct Sig : public FunType {}; template typename L::ElementType operator()( const L& l ) const { return foldl1( Max(), l ); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Maximum maximum; FCPP_MAYBE_NAMESPACE_CLOSE #ifdef FCPP_SIMPLE_PRELUDE struct ZipWith { 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( ZipWith(), z, tail(a), tail(b) ) ); } }; #else struct ZipWith { 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( ZipWith(), z, tail(a), tail(b) ) ); } }; #endif FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN ZipWith _zipWith; FCPP_MAYBE_EXTERN Curryable3 zipWith FCPP_MAYBE_INIT((_zipWith)); FCPP_MAYBE_NAMESPACE_CLOSE struct Zip { template struct Sig : public FunType > > {}; template OddList > operator()( const LA& a, const LB& b ) const { return zipWith( MakePair(), a, b ); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Zip _zip; FCPP_MAYBE_EXTERN Curryable2 zip FCPP_MAYBE_INIT((_zip)); FCPP_MAYBE_NAMESPACE_CLOSE struct Fst { template struct Sig : public FunType {}; template A operator()( const std::pair& p ) const { return p.first; } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Fst fst; FCPP_MAYBE_NAMESPACE_CLOSE struct Snd { template struct Sig : public FunType {}; template B operator()( const std::pair& p ) const { return p.second; } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Snd snd; FCPP_MAYBE_NAMESPACE_CLOSE struct Unzip { 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)) ); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Unzip unzip; FCPP_MAYBE_NAMESPACE_CLOSE struct GcdPrime { 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 Gcd { 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 GcdPrime()( x<0?-x:x, y<0?-y:y ); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Gcd _gcd; FCPP_MAYBE_EXTERN Curryable2 gcd FCPP_MAYBE_INIT((_gcd)); FCPP_MAYBE_NAMESPACE_CLOSE struct Odd { template struct Sig : public FunType {}; template bool operator()( const T& x ) const { return x%2==1; } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Odd odd; FCPP_MAYBE_NAMESPACE_CLOSE struct Even { template struct Sig : public FunType {}; template bool operator()( const T& x ) const { return x%2==0; } }; 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. #ifdef FCPP_TEMPLATE_ENUM template struct EFH : public Fun0Impl< OddList > { mutable T x; EFH( const T& xx ) : x(xx) {} OddList operator()() const { ++x; return cons( x-1, Fun0 >(1,this) ); } }; struct EnumFrom { template struct Sig : FunType > {}; template List operator()( const T& x ) const { return Fun0 >(1, new EFH(x) ); } }; #else struct EFH : public Fun0Impl< OddList > { mutable int x; EFH( int xx ) : x(xx) {} OddList operator()() const { ++x; return cons( x-1, Fun0 >(1,this) ); } }; struct EnumFrom : CFunType > { List operator()( int x ) const { return Fun0 >(1, new EFH(x) ); } }; #endif FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN EnumFrom enumFrom; FCPP_MAYBE_NAMESPACE_CLOSE #ifdef FCPP_TEMPLATE_ENUM template struct EFTH : public Fun0Impl > { mutable T x; T y; EFTH( 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 EnumFromTo { template struct Sig; template struct Sig : FunType > {}; template List operator()( const T& x, const T& y ) const { return Fun0 >( 1, new EFTH(x,y) ); } }; #else struct EFTH : public Fun0Impl > { mutable int x; int y; EFTH( 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 EnumFromTo : CFunType > { List operator()( const int& x, const int& y ) const { return Fun0 >( 1, new EFTH(x,y) ); } }; #endif FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN EnumFromTo _enumFromTo; FCPP_MAYBE_EXTERN Curryable2 enumFromTo FCPP_MAYBE_INIT((_enumFromTo)); FCPP_MAYBE_NAMESPACE_CLOSE // Not HSP struct ListUntil { 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) ); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN ListUntil _listUntil; FCPP_MAYBE_EXTERN Curryable3 listUntil FCPP_MAYBE_INIT((_listUntil)); FCPP_MAYBE_NAMESPACE_CLOSE ////////////////////////////////////////////////////////////////////// // The "Maybe" type, from Haskell ////////////////////////////////////////////////////////////////////// template class Maybe { OddList rep; public: Maybe() {} // the Nothing constructor Maybe( const T& x ) : rep( cons(x,NIL) ) {} // the Just constructor bool is_nothing() const { return !rep; } T value() const { return head(rep); } }; // 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() ) struct NoOp : public CFunType { void operator()() const {} }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN NoOp noOp; FCPP_MAYBE_NAMESPACE_CLOSE template class BeforerBase { protected: F f; G g; BeforerBase( const F& ff, const G& gg ) : f(ff), g(gg) {} }; template class BeforerMixin : public CallableWithoutArguments, public BeforerBase { protected: using BeforerBase::f; using BeforerBase::g; BeforerMixin( const F& ff, const G& gg ) : BeforerBase(ff,gg) {} public: typename RT::ResultType operator()() const { f(); return g(); } }; template class BeforerMixin : public BeforerBase { protected: using BeforerBase::f; using BeforerBase::g; BeforerMixin( const F& ff, const G& gg ) : BeforerBase(ff,gg) {} template struct Impossible {}; public: template void operator()( Impossible& ) {} }; template class Beforer : public BeforerMixin::value> { typedef BeforerMixin::value> Super; using Super::f; using Super::g; public: #ifndef FCPP_NO_USING_DECLS using Super::operator(); #endif Beforer( const F& ff, const G& gg ) : Super(ff,gg) {} template struct Sig : FunType::Arg1Type, typename RT::Arg2Type, typename RT::Arg3Type, typename RT::ResultType> {}; template struct Sig : FunType::Arg1Type, typename RT::Arg2Type, typename RT::ResultType> {}; template struct Sig : FunType::Arg1Type, typename RT::ResultType> {}; template struct Sig : FunType::ResultType> {}; template typename Sig::ResultType operator()( const X& x ) const { f(); return g(x); } template typename Sig::ResultType operator()( const X& x, const Y& y ) const { f(); return g(x,y); } template typename Sig::ResultType operator()( const X& x, const Y& y, const Z& z ) const { f(); return g(x,y,z); } }; struct Before { template struct Sig : public FunType > {}; template Beforer operator()( const F& f, const G& g ) const { return Beforer( f, g ); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Before before_; FCPP_MAYBE_EXTERN Curryable2 before FCPP_MAYBE_INIT((before_)); FCPP_MAYBE_NAMESPACE_CLOSE template class AftererBase { protected: F f; G g; AftererBase( const F& ff, const G& gg ) : f(ff), g(gg) {} }; template class AftererMixin : public CallableWithoutArguments, public AftererBase { protected: using AftererBase::f; using AftererBase::g; AftererMixin( const F& ff, const G& gg ) : AftererBase(ff,gg) {} public: typename RT::ResultType operator()() const { typename RT::ResultType res( f() ); g(); return res; } }; template class AftererMixin : public AftererBase { protected: using AftererBase::f; using AftererBase::g; AftererMixin( const F& ff, const G& gg ) : AftererBase(ff,gg) {} template struct Impossible {}; public: template void operator()( Impossible& ) {} }; template class Afterer : public AftererMixin::value> { typedef AftererMixin::value> Super; using Super::f; using Super::g; public: #ifndef FCPP_NO_USING_DECLS using Super::operator(); #endif Afterer( const F& ff, const G& gg ) : Super(ff,gg) {} template struct Sig : FunType::Arg1Type, typename RT::Arg2Type, typename RT::Arg3Type, typename RT::ResultType> {}; template struct Sig : FunType::Arg1Type, typename RT::Arg2Type, typename RT::ResultType> {}; template struct Sig : FunType::Arg1Type, typename RT::ResultType> {}; template struct Sig : FunType::ResultType> {}; template typename Sig::ResultType operator()( const X& x ) const { typename RT::ResultType res( f(x) ); g(); return res; } template typename Sig::ResultType operator()( const X& x, const Y& y ) const { typename RT::ResultType res( f(x,y) ); g(); return res; } template typename Sig::ResultType operator()( const X& x, const Y& y, const Z& z ) const { typename RT::ResultType res( f(x,y,z) ); g(); return res; } }; struct After { template struct Sig : public FunType > {}; template Afterer operator()( const F& f, const G& g ) const { return Afterer( f, g ); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN After after_; FCPP_MAYBE_EXTERN Curryable2 after FCPP_MAYBE_INIT((after_)); FCPP_MAYBE_NAMESPACE_CLOSE ////////////////////////////////////////////////////////////////////// // 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. // // Note that uncurry() (as well as curryN()) means something different // in FC++ than what it does in Haskell. template class UncurryableBase { protected: F f; UncurryableBase( const F& ff ) : f(ff) {} }; template class UncurryableMixin : public CallableWithoutArguments, public UncurryableBase { protected: using UncurryableBase::f; UncurryableMixin ( const F& ff ) : UncurryableBase(ff) {} public: typename RT::ResultType operator()() const { return f(); } }; template class UncurryableMixin : public UncurryableBase { protected: using UncurryableBase::f; UncurryableMixin ( const F& ff ) : UncurryableBase(ff) {} template struct Impossible {}; public: template void operator()( Impossible& ) {} }; template class Uncurryable : public UncurryableMixin::value> { typedef UncurryableMixin::value> Super; using Super::f; public: #ifndef FCPP_NO_USING_DECLS using Super::operator(); #endif Uncurryable( const F& ff ) : Super(ff) {} 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 struct Sig : FunType::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); } }; struct Uncurry { template struct Sig : FunType > {}; template Uncurryable operator()( const F& f ) const { return Uncurryable(f); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Uncurry uncurry; 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) template class Duplicater { F f; public: Duplicater( 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 Duplicate { template struct Sig : public FunType > {}; template Duplicater operator()( const F& f ) const { return Duplicater(f); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Duplicate duplicate; FCPP_MAYBE_NAMESPACE_CLOSE template class Ignorer { F f; public: Ignorer( const F& ff ) : f(ff) {} template struct Sig : public FunType {}; template F operator()( const X& ) const { return f; } }; template class Ignorer { F f; public: Ignorer( const F& ff ) : f(ff) {} template struct Sig : public FunType::ResultType> {}; template typename RT::ResultType operator()( const X& ) const { return f(); } }; struct Ignore { template struct Sig : public FunType::value> > > {}; template typename Sig::ResultType operator()( const F& f ) const { return uncurry( Ignorer::value>(f) ); } }; 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) template struct Construct0 : public CFunType { T operator()() const { return T(); } }; template Construct0 construct0() { return Construct0(); } template struct Construct1 { template struct Sig : FunType {}; template T operator()( const X& x ) const { return T(x); } }; template Construct1 construct1() { return Construct1(); } template struct Construct2 { template struct Sig : FunType {}; template T operator()( const X& x, const Y& y ) const { return T(x,y); } }; template Curryable2 > construct2() { return makeCurryable2( Construct2() ); } template struct Construct3 { template struct Sig : FunType {}; template T operator()( const X& x, const Y& y, const Z& z ) const { return T(x,y,z); } }; template Curryable3 > construct3() { return makeCurryable3( Construct3() ); } // NewN works like ConstructN but "new"s it and returns the ptr template struct New0 : public CFunType { T* operator()() const { return new T(); } }; template New0 new0() { return New0(); } template struct New1 { template struct Sig : FunType {}; template T* operator()( const X& x ) const { return new T(x); } }; template New1 new1() { return New1(); } template struct New2 { template struct Sig : FunType {}; template T* operator()( const X& x, const Y& y ) const { return new T(x,y); } }; template Curryable2 > new2() { return makeCurryable2( New2() ); } template struct New3 { template struct Sig : FunType {}; template T* operator()( const X& x, const Y& y, const Z& z ) const { return new T(x,y,z); } }; template Curryable3 > new3() { return makeCurryable3( New3() ); } } // end namespace fcpp #endif