// // Copyright (c) 2000,2001 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 few 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 { template class Compose0Helper { F f; G g; public: Compose0Helper( const F& a, const G& b ) : f(a), g(b) {} struct Sig : public FunType< typename F::template Sig::ResultType > {}; typename F::template Sig::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 Compose1Helper { F f; G g; public: Compose1Helper( const F& a, const G& b ) : f(a), g(b) {} template struct Sig : public FunType< typename G::template Sig::Arg1Type, typename F::template Sig::ResultType>::ResultType > {}; template typename F::template Sig::ResultType>::ResultType operator()( const T& x ) const { return f( g(x) ); } }; // Compose1 is Haskell's operator (.) for f.g where g is a one-arg struct Compose1 { template struct Sig : public FunType > {}; template Compose1Helper operator()( const F& f, const G& g ) const { return Compose1Helper( f, g ); } }; namespace { Compose1 compose1, compose; } 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 ); } }; namespace { Compose2 _compose2; Curryable3 compose2(_compose2); } 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; } }; namespace { Until _until; Curryable3 until(_until); } struct Last { template struct Sig : public FunType {}; template T operator()( List l ) const { while( !null( tail(l) ) ) l = tail(l); return head(l); } }; namespace { Last last; } #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 namespace { Init init; } struct Length { template struct Sig : public FunType {}; template size_t operator()( List l ) const { size_t x = 0; while( !null(l) ) { l = tail(l); ++x; } return x; } }; namespace { Length length; } // 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); } }; namespace { At _at; Curryable2 at(_at); } #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 namespace { Filter _filter; Curryable2 filter(_filter); } #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 namespace { Concat concat; } // 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 List& l ) const { if( null(l) ) return e; else return op( head(l), Foldr()( op, e, tail(l) ) ); } }; namespace { Foldr _foldr; Curryable3 foldr(_foldr); } struct Foldr1 { template struct Sig : public FunType {}; template T operator()( const Op& op, const List& l ) const { return foldr( op, head(l), tail(l) ); } }; namespace { Foldr1 _foldr1; Curryable2 foldr1(_foldr1); } struct Foldl { template struct Sig : public FunType {}; template E operator()( const Op& op, E e, List l ) const { while( !null(l) ) { E tmp( e ); e.~E(); new (&e) E( op(tmp,head(l)) ); l = tail(l); } return e; } }; namespace { Foldl _foldl; Curryable3 foldl(_foldl); } struct Foldl1 { template struct Sig : public FunType {}; template T operator()( const Op& op, const List& l ) const { return foldl( op, head(l), tail(l) ); } }; namespace { Foldl1 _foldl1; Curryable2 foldl1(_foldl1); } 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 ); } } }; namespace { Scanr _scanr; Curryable3 scanr(_scanr); } 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 ); } } }; namespace { Scanr1 _scanr1; Curryable2 scanr1(_scanr1); } #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 namespace { Scanl _scanl; Curryable3 scanl(_scanl); } struct Scanl1 { template struct Sig : public FunType > {}; template OddList operator()( const Op& op, const L& l ) const { return scanl( op, head(l), tail(l) ); } }; namespace { Scanl1 _scanl1; Curryable2 scanl1(_scanl1); } #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 namespace { Iterate _iterate; Curryable2 iterate(_iterate); } #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 namespace { Repeat repeat; } #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 namespace { Map _map; Curryable2 map(_map); } #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 namespace { Take _take; Curryable2 take(_take); } struct Drop { template struct Sig : public FunType > {}; template List operator()( size_t n, List l ) const { while( n!=0 && !null(l) ) { --n; l = tail(l); } return l; } }; namespace { Drop _drop; Curryable2 drop(_drop); } #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 namespace { TakeWhile _takeWhile; Curryable2 takeWhile(_takeWhile); } struct DropWhile { template struct Sig : public FunType > {}; template List operator()( const P& p, List l ) const { while( !null(l) && p( head(l) ) ) l = tail(l); return l; } }; namespace { DropWhile _dropWhile; Curryable2 dropWhile(_dropWhile); } struct Replicate { template struct Sig : public FunType > {}; template OddList operator()( size_t n, const T& x ) const { return take( n, repeat(x) ); } }; namespace { Replicate _replicate; Curryable2 replicate(_replicate); } #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 namespace { Cycle cycle; } 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 ); } } }; namespace { SplitAt _splitAt; Curryable2 splitAt(_splitAt); } 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 ); } } }; namespace { Span _span; Curryable2 span(_span); } struct Break { template struct Sig : public FunType,List > > {}; template std::pair,List > operator()( const P& p, const List& l ) const { return span( Compose1()( LogicalNot(), p ), l ); } }; namespace { Break _break_; Curryable2 break_(_break_); // C++ keyword, so add trailing underscore } 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 FlipHelper operator()( const Binary& op ) const { return FlipHelper( op ); } }; namespace { Flip flip; } struct Reverse { template struct Sig : public FunType > {}; template List operator()( const List& l ) const { return curry3( foldl, flip(cons), List(), l ); } }; namespace { Reverse reverse; } ////////////////////////////////////////////////////////////////////// // Not HSP but close ////////////////////////////////////////////////////////////////////// // These next two are defined as _lazy_ versions of these operators on lists // We don't give them names because they conflict with C++ operators struct And : public CFunType,bool> { bool operator()( const List& l ) const { return null(dropWhile( curry2(Equal(),true), l )); } }; struct Or : public CFunType,bool> { bool operator()( const List& l ) const { return !null(dropWhile( curry2(Equal(),false), l )); } }; ////////////////////////////////////////////////////////////////////// // 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 ) ); } }; namespace { All _all; Curryable2 all(_all); } struct Any { template struct Sig : public FunType {}; template bool operator()( const P& p, const L& l ) const { return Or()( map( p, l ) ); } }; namespace { Any _any; Curryable2 any(_any); } struct Elem { template struct Sig : public FunType {}; template bool operator()( const T& x, const L& l ) const { return any( bind2of2( Equal(), x ), l ); } }; namespace { Elem _elem; Curryable2 elem(_elem); } struct NotElem { template struct Sig : public FunType {}; template bool operator()( const T& x, const L& l ) const { return all( bind2of2( NotEqual(), x ), l ); } }; namespace { NotElem _notElem; Curryable2 notElem(_notElem); } struct Sum { template struct Sig : public FunType {}; template typename L::ElementType operator()( const L& l ) const { return foldl( Plus(), 0, l ); } }; namespace { Sum sum; } struct Product { template struct Sig : public FunType {}; template typename L::ElementType operator()( const L& l ) const { return foldl( Multiplies(), 1, l ); } }; namespace { Product product; } struct Minimum { template struct Sig : public FunType {}; template typename L::ElementType operator()( const L& l ) const { return foldl1( Min(), l ); } }; namespace { Minimum minimum; } struct Maximum { template struct Sig : public FunType {}; template typename L::ElementType operator()( const L& l ) const { return foldl1( Max(), l ); } }; namespace { Maximum maximum; } #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 namespace { ZipWith _zipWith; Curryable3 zipWith(_zipWith); } struct Zip { template struct Sig : public FunType > > {}; template OddList > operator()( const LA& a, const LB& b ) const { return zipWith( MakePair(), a, b ); } }; namespace { Zip _zip; Curryable2 zip(_zip); } struct Fst { template struct Sig : public FunType {}; template A operator()( const std::pair& p ) const { return p.first; } }; namespace { Fst fst; } struct Snd { template struct Sig : public FunType {}; template B operator()( const std::pair& p ) const { return p.second; } }; namespace { Snd snd; } 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)) ); } }; namespace { Unzip unzip; } 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 ); } }; namespace { Gcd _gcd; Curryable2 gcd(_gcd); } struct Odd { template struct Sig : public FunType {}; template bool operator()( const T& x ) const { return x%2==1; } }; namespace { Odd odd; } struct Even { template struct Sig : public FunType {}; template bool operator()( const T& x ) const { return x%2==0; } }; namespace { Even even; } ////////////////////////////////////////////////////////////////////// // 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 namespace { EnumFrom enumFrom; } #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 namespace { EnumFromTo _enumFromTo; Curryable2 enumFromTo(_enumFromTo); } // Not HSP struct ListUntil { template struct Sig : public FunType > {}; template List operator()( const Pred& p, const Unary& f, const T& x ) const { return takeWhile( fcpp::compose(logicalNot,p), iterate(f,x) ); } }; namespace { ListUntil _listUntil; Curryable3 listUntil(_listUntil); } } // end namespace fcpp #endif