// // 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_CURRY_DOT_H #define FCPP_CURRY_DOT_H #include "signature.h" namespace fcpp { ////////////////////////////////////////////////////////////////////// // This file implements currying for functoids. Included here are // - bindMofN for currying the Mth of N arguments // - Const for turning a value into a constant function // - curryN curries the first k arguments of an N-arg functoid, // where k is the number of arguments "curryN" was // called with // - CurryableN new way to curry with underscores (e.g. f(_,y,_); ) // // For more info, see // http://www.cc.gatech.edu/~yannis/fc++/currying.html ////////////////////////////////////////////////////////////////////// // Important to implementation of CurryableN classes struct AutoCurryType {}; FCPP_MAYBE_EXTERN AutoCurryType _; // this is a legal identifier as fcpp::_ // Forward declarations; curryability and fullness are now somewhat // inextricably intertwined... template struct Full0; template struct Full1; template struct Full2; template struct Full3; template Full0 makeFull0( const F& f ); template Full1 makeFull1( const F& f ); template Full2 makeFull2( const F& f ); template Full3 makeFull3( const F& f ); namespace impl { ////////////////////////////////////////////////////////////////////// // Const ////////////////////////////////////////////////////////////////////// template struct ConstHelper : public CFunType { const T x; public: ConstHelper( const T& a ) : x(a) {} T operator()() const { return x; } }; struct Const { template struct Sig : public FunType > > {}; template Full0 > operator()( const T& x ) const { return makeFull0( ConstHelper(x) ); } }; ////////////////////////////////////////////////////////////////////// // Binders (through "...of2") ////////////////////////////////////////////////////////////////////// template class binder1of1 : public CFunType::ResultType> { const Unary f; const Arg a; public: binder1of1( const Unary& x, const Arg& y ) : f(x), a(y) {} typename RT::ResultType operator()() const { return f(a); } }; struct Bind1of1 { template struct Sig : public FunType< Unary, Arg, Full0 > > {}; template inline Full0 > operator()( const Unary& f, const Arg& a ) const { return makeFull0( binder1of1(f,a) ); } }; template class binder1of2 { const Binary f; const Arg1 x; public: binder1of2( const Binary& a, const Arg1& b ) : f(a), x(b) {} template struct Sig : public FunType::Arg2Type, typename Binary::template Sig::ResultType> {}; template typename Binary::template Sig::ResultType operator()( const Arg2& y ) const { return f(x,y); } }; struct Bind1of2 { template struct Sig : public FunType > > {}; template Full1 > operator()( const Binary& f, const Arg1& x ) const { return makeFull1( binder1of2(f,x) ); } }; template class binder2of2 { const Binary f; const Arg2 y; public: binder2of2( const Binary& a, const Arg2& b ) : f(a), y(b) {} template struct Sig : public FunType::Arg1Type, typename Binary::template Sig::ResultType> {}; template typename Binary::template Sig::ResultType operator()( const Arg1& x ) const { return f(x,y); } }; struct Bind2of2 { template struct Sig : public FunType > > {}; template Full1 > operator()( const Binary& f, const Arg2& y ) const { return makeFull1( binder2of2(f,y) ); } }; template class binder1and2of2 : public CFunType::ResultType > { const Binary f; const Arg1 a1; const Arg2 a2; public: binder1and2of2( const Binary& x, const Arg1& y, const Arg2& z ) : f(x), a1(y), a2(z) {} typename RT::ResultType operator()() const { return f(a1,a2); } }; struct Bind1and2of2 { template struct Sig : public FunType< Binary, Arg1, Arg2, Full0 > > {}; template Full0 > operator()( const Binary& f, const Arg1& a1, const Arg2& a2 ) const { return makeFull0( binder1and2of2(f,a1,a2) ); } }; ////////////////////////////////////////////////////////////////////// // Now that bindNof2 are defined, we can define Curryable2, which then // some of the later binders can use. ////////////////////////////////////////////////////////////////////// template struct Curryable2Helper { static inline R go( const F& f, const X& x, const Y& y ) { return f(x,y); } }; template struct Curryable2Helper { static R go( const F& f, const AutoCurryType& , const Y& y ) { return makeFull1( binder2of2(f,y) ); } }; template struct Curryable2Helper { static R go( const F& f, const X& x, const AutoCurryType& ) { return makeFull1( binder1of2(f,x) ); } }; template class Curryable2 { const F f; public: Curryable2( const F& ff ) : f(ff) {} template struct Sig : public FunType::Arg1Type, typename F::template Sig::Arg2Type, typename RT::ResultType> {}; template struct Sig : public FunType > > {}; template struct Sig : public FunType > > {}; template struct Sig : public FunType > > {}; template typename Sig::ResultType operator()( const X& x ) const { return makeFull1( binder1of2(f,x) ); } template inline typename Sig::ResultType operator()( const X& x, const Y& y ) const { // need partial specialization, so defer to a class helper return Curryable2Helper::ResultType,F,X,Y>::go(f,x,y); } }; ////////////////////////////////////////////////////////////////////// // With Curryable2 out of the way, we can go back to the 3-arg binders. ////////////////////////////////////////////////////////////////////// template class binder1and2and3of3 : public CFunType::ResultType> { const Ternary f; const A1 a1; const A2 a2; const A3 a3; public: binder1and2and3of3( const Ternary& w, const A1& x, const A2& y, const A3& z ) : f(w), a1(x), a2(y), a3(z) {} typename RT::ResultType operator()() const { return f(a1,a2,a3); } }; struct Bind1and2and3of3 { template struct Sig : public FunType > > {}; template Full0 > operator()( const Ternary& f, const A1& a1, const A2& a2, const A3& a3 ) const { return makeFull0( binder1and2and3of3(f,a1,a2,a3) ); } }; template class binder1and2of3 { const Ternary f; const Arg1 a1; const Arg2 a2; public: template struct Sig : public FunType::Arg3Type, typename Ternary::template Sig::ResultType> {}; binder1and2of3(const Ternary& w, const Arg1& x, const Arg2& y) : f(w), a1(x), a2(y) {} template typename Sig::ResultType operator()(const Arg3& z) const { return f(a1,a2,z); } }; struct Bind1and2of3 { template struct Sig : public FunType > > {}; template Full1 > operator()( const Ternary& f, const A1& a1, const A2& a2 ) const { return makeFull1( binder1and2of3(f,a1,a2) ); } }; template class binder2and3of3 { const Ternary f; const Arg2 a2; const Arg3 a3; public: template struct Sig : public FunType::Arg1Type, typename RT::ResultType> {}; // need RT above due to g++ bug on line below // typename Ternary::Sig::ResultType> {}; binder2and3of3(const Ternary& w, const Arg2& y, const Arg3& z) : f(w), a2(y), a3(z) {} template typename Sig::ResultType operator()(const Arg1& x) const { return f(x,a2,a3); } }; struct Bind2and3of3 { template struct Sig : public FunType > > {}; template Full1 > operator()( const Ternary& f, const A2& a2, const A3& a3 ) const { return makeFull1( binder2and3of3(f,a2,a3) ); } }; template class binder1and3of3 { const Ternary f; const Arg1 a1; const Arg3 a3; public: template struct Sig : public FunType::Arg2Type, typename RT::ResultType> {}; // need RT above due to g++ bug on line below // typename Ternary::Sig::ResultType> {}; binder1and3of3(const Ternary& w, const Arg1& x, const Arg3& z) : f(w), a1(x), a3(z) {} template typename Sig::ResultType operator()(const Arg2& y) const { return f(a1,y,a3); } }; struct Bind1and3of3 { template struct Sig : public FunType > > {}; template Full1 > operator()( const Ternary& f, const A1& a1, const A3& a3 ) const { return makeFull1( binder1and3of3(f,a1,a3) ); } }; template class binder1of3 { const Ternary f; const Arg1 x; public: binder1of3( const Ternary& a, const Arg1& b ) : f(a), x(b) {} template struct Sig : public FunType::Arg2Type, typename Ternary::template Sig::Arg3Type, typename Ternary::template Sig::ResultType> {}; template typename RT::ResultType operator()( const Arg2& y, const Arg3& z ) const { return f(x,y,z); } }; struct Bind1of3 { template struct Sig : public FunType > > {}; template typename Sig::ResultType operator()( const Ternary& f, const Arg1& x ) const { return makeFull2( binder1of3(f,x) ); } }; template class binder2of3 { const Ternary f; const Arg2 x; public: binder2of3( const Ternary& a, const Arg2& b ) : f(a), x(b) {} template struct Sig : public FunType::Arg1Type, typename Ternary::template Sig::Arg3Type, typename Ternary::template Sig::ResultType> {}; template typename RT::ResultType operator()( const Arg1& y, const Arg3& z ) const { return f(y,x,z); } }; struct Bind2of3 { template struct Sig : public FunType > > {}; template typename Sig::ResultType operator()( const Ternary& f, const Arg2& x ) const { return makeFull2( binder2of3(f,x) ); } }; template class binder3of3 { const Ternary f; const Arg3 x; public: binder3of3( const Ternary& a, const Arg3& b ) : f(a), x(b) {} template struct Sig : public FunType::Arg1Type, typename Ternary::template Sig::Arg2Type, typename Ternary::template Sig::ResultType> {}; template typename RT::ResultType operator()( const Arg1& y, const Arg2& z ) const { return f(y,z,x); } }; struct Bind3of3 { template struct Sig : public FunType > > {}; template typename Sig::ResultType operator()( const Ternary& f, const Arg3& x ) const { return makeFull2( binder3of3(f,x) ); } }; ////////////////////////////////////////////////////////////////////// // "curry" versions. Now that we have auto-currying, you rarely need to // call curry() explicitly, unless you are trying to get lazy evaulation // in examples like // curry2( map, f, l ). // It used to be the case that you might also do // curry2( map, f ), // but nowadays you can say the same thing with just // map(f). ////////////////////////////////////////////////////////////////////// struct Curry3 { template struct Sig : public FunType > > {}; template struct Sig : public FunType > > {}; template struct Sig : public FunType > > {}; template typename Sig::ResultType operator()( const Ternary& f, const A1& a1, const A2& a2, const A3& a3 ) const { return makeFull0( binder1and2and3of3(f,a1,a2,a3) ); } template typename Sig::ResultType operator()( const Ternary& f, const A1& a1, const A2& a2 ) const { return makeFull1( binder1and2of3(f,a1,a2) ); } template typename Sig::ResultType operator()( const Ternary& f, const A1& a1 ) const { return makeFull2( binder1of3(f,a1) ); } }; struct Curry2 { template struct Sig : public FunType > > {}; template struct Sig : public FunType > > {}; template typename Sig::ResultType operator()( const Binary& f, const A1& a1, const A2& a2 ) const { return makeFull0( binder1and2of2(f,a1,a2) ); } template typename Sig::ResultType operator()( const Binary& f, const A1& a1 ) const { return makeFull1( binder1of2(f,a1) ); } }; struct Curry1 { template struct Sig : public FunType > > {}; template typename Sig::ResultType operator()( const Unary& f, const A1& a1 ) const { return makeFull0( binder1of1(f,a1) ); } }; ////////////////////////////////////////////////////////////////////// // Finally, Curryable3 (what a huge beast) ////////////////////////////////////////////////////////////////////// template struct Curryable3Helper { static inline R go( const F& f, const X& x, const Y& y, const Z& z ) { return f(x,y,z); } }; template struct Curryable3Helper { static R go( const F& f, const X& x, const AutoCurryType&, const AutoCurryType& ) { return makeFull2( binder1of3(f,x) ); } }; template struct Curryable3Helper { static R go( const F& f, const AutoCurryType&, const Y& y, const AutoCurryType& ) { return makeFull2( binder2of3(f,y) ); } }; template struct Curryable3Helper { static R go( const F& f, const AutoCurryType&, const AutoCurryType&, const Z& z ) { return makeFull2( binder3of3(f,z) ); } }; template struct Curryable3Helper { static R go( const F& f, const AutoCurryType&, const Y& y, const Z& z ) { return makeFull1( binder2and3of3(f,y,z) ); } }; template struct Curryable3Helper { static R go( const F& f, const X& x, const AutoCurryType&, const Z& z ) { return makeFull1( binder1and3of3(f,x,z) ); } }; template struct Curryable3Helper { static R go( const F& f, const X& x, const Y& y, const AutoCurryType& ) { return makeFull1( binder1and2of3(f,x,y) ); } }; template struct Curryable3Helper2 { static R go( const F& f, const X& x, const Y& y ) { return makeFull1( binder1and2of3(f,x,y) ); } }; template struct Curryable3Helper2 { static R go( const F& f, const AutoCurryType&, const Y& y ) { return makeFull2(binder2of3(f,y)); } }; template struct Curryable3Helper2 { static R go( const F& f, const X& x, const AutoCurryType& ) { return makeFull2(binder1of3(f,x)); } }; template class Curryable3 { const F f; public: Curryable3( const F& ff ) : f(ff) {} template struct Sig : public FunType::Arg1Type, typename F::template Sig::Arg2Type, typename F::template Sig::Arg3Type, typename RT::ResultType> {}; template struct Sig : public FunType > > {}; template struct Sig : public FunType > > {}; template struct Sig : public FunType > > {}; template struct Sig : public FunType > > {}; template struct Sig : public FunType > > {}; template struct Sig : public FunType > > {}; template struct Sig : public FunType > > {}; template struct Sig : public FunType > > {}; template struct Sig : public FunType > > {}; template struct Sig : public FunType > > {}; template typename Sig::ResultType operator()( const X& x, const Y& y ) const { // need partial specialization, so defer to a class helper return Curryable3Helper2::ResultType,F,X,Y>::go(f,x,y); } template typename Sig::ResultType operator()( const X& x ) const { return makeFull2(binder1of3(f,x)); } template inline typename Sig::ResultType operator()( const X& x, const Y& y, const Z& z ) const { // need partial specialization, so defer to a class helper return Curryable3Helper::ResultType,F,X,Y,Z>::go(f,x,y,z); } }; } // end namespace impl using impl::Curryable2; using impl::Curryable3; using impl::Curry3; using impl::Curry2; using impl::Curry1; // FIX THIS: the CurryNs are not Full functoids. Oh well. FCPP_MAYBE_EXTERN Curry1 curry1, curry; // "curry" is the same as "curry1" FCPP_MAYBE_EXTERN Curry2 curry2; FCPP_MAYBE_EXTERN Curry3 curry3; // FIX THIS These are deprecated; use makeFullN instead template Curryable2 makeCurryable2( const F& f ) { return Curryable2( f ); } template Curryable3 makeCurryable3( const F& f ) { return Curryable3( f ); } } // end namespace fcpp #endif