// // 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_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_NAMESPACE_OPEN FCPP_MAYBE_EXTERN AutoCurryType _; // this is a legal identifier as fcpp::_ FCPP_MAYBE_NAMESPACE_CLOSE ////////////////////////////////////////////////////////////////////// // 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 ConstHelper operator()( const T& x ) const { return ConstHelper(x); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Const const_; // C++ keyword, so add trailing underscore FCPP_MAYBE_NAMESPACE_CLOSE ////////////////////////////////////////////////////////////////////// // 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, binder1of1 > {}; template inline binder1of1 operator()( const Unary& f, const Arg& a ) const { return binder1of1(f,a); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Bind1of1 bind1of1; //Curryable2 bind1of1(_bind1of1); FCPP_MAYBE_NAMESPACE_CLOSE 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 binder1of2 operator()( const Binary& f, const Arg1& x ) const { return binder1of2(f,x); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Bind1of2 bind1of2; //Curryable2 bind1of2(_bind1of2); FCPP_MAYBE_NAMESPACE_CLOSE 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 binder2of2 operator()( const Binary& f, const Arg2& y ) const { return binder2of2(f,y); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Bind2of2 bind2of2; //Curryable2 bind2of2(_bind2of2); FCPP_MAYBE_NAMESPACE_CLOSE 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, binder1and2of2 > {}; template binder1and2of2 operator()( const Binary& f, const Arg1& a1, const Arg2& a2 ) const { return binder1and2of2(f,a1,a2); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Bind1and2of2 bind1and2of2; //Curryable3 bind1and2of2(_bind1and2of2); FCPP_MAYBE_NAMESPACE_CLOSE ////////////////////////////////////////////////////////////////////// // Now that bindNof2 are defined, we can define Curryable2, which then // some of the later binders can use. ////////////////////////////////////////////////////////////////////// template struct Curryable2Helper { R operator()( const F& f, const X& x, const Y& y ) const { return f(x,y); } }; template struct Curryable2Helper { R operator()( const F& f, const AutoCurryType& , const Y& y ) const { return binder2of2(f,y); } }; template struct Curryable2Helper { R operator()( const F& f, const X& x, const AutoCurryType& ) const { return 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> {}; // Note: the line below is incorrect, as Fun2 uses AnyType, for example //: public FunType::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 binder1of2(f,x); } template 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>()(f,x,y); } }; template Curryable2 makeCurryable2( const F& f ) { return Curryable2( f ); } ////////////////////////////////////////////////////////////////////// // 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 binder1and2and3of3 operator()( const Ternary& f, const A1& a1, const A2& a2, const A3& a3 ) const { return binder1and2and3of3(f,a1,a2,a3); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Bind1and2and3of3 bind1and2and3of3; FCPP_MAYBE_NAMESPACE_CLOSE 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 binder1and2of3 operator()( const Ternary& f, const A1& a1, const A2& a2 ) const { return binder1and2of3(f,a1,a2); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Bind1and2of3 bind1and2of3; //Curryable3 bind1and2of3(_bind1and2of3); FCPP_MAYBE_NAMESPACE_CLOSE 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 binder2and3of3 operator()( const Ternary& f, const A2& a2, const A3& a3 ) const { return binder2and3of3(f,a2,a3); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Bind2and3of3 bind2and3of3; //Curryable3 bind2and3of3(_bind2and3of3); FCPP_MAYBE_NAMESPACE_CLOSE 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 binder1and3of3 operator()( const Ternary& f, const A1& a1, const A3& a3 ) const { return binder1and3of3(f,a1,a3); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Bind1and3of3 bind1and3of3; //Curryable3 bind1and3of3(_bind1and3of3); FCPP_MAYBE_NAMESPACE_CLOSE 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); } }; // FIX THIS: "BindNof3"s should really be "Curryable2"s, so that stuff // like ternary(_,_,3)(1)(2) works... ugh. // // Yuck. What should happen is that "bind1of3" should have type // "Curryable2", but in a number of places in the library, I // bet I have presumed that the return type of bind1of3(...) was // going to be a "binder1of3" and then implemented based on that // (soon-to-be-faulty) presumption. Argh. I should really make the // "Binder" classes hidden inside another namespace to prevent idiots // like me from assuming things--they are implementation details of the // "bindNof3" interface, and I shouldn't know about them. // // Darn. // // Ok, so at some point, I need to go back and find all the // "implementation details" and hide them in a nested namespace named // "implementation" or something. struct Bind1of3 { template struct Sig : public FunType > > {}; template typename Sig::ResultType operator()( const Ternary& f, const Arg1& x ) const { return makeCurryable2( binder1of3(f,x) ); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Bind1of3 _bind1of3; FCPP_MAYBE_EXTERN Curryable2 bind1of3 FCPP_MAYBE_INIT((_bind1of3)); FCPP_MAYBE_NAMESPACE_CLOSE 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 makeCurryable2( binder2of3(f,x) ); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Bind2of3 _bind2of3; FCPP_MAYBE_EXTERN Curryable2 bind2of3 FCPP_MAYBE_INIT((_bind2of3)); FCPP_MAYBE_NAMESPACE_CLOSE 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 makeCurryable2( binder3of3(f,x) ); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Bind3of3 _bind3of3; FCPP_MAYBE_EXTERN Curryable2 bind3of3 FCPP_MAYBE_INIT((_bind3of3)); FCPP_MAYBE_NAMESPACE_CLOSE ////////////////////////////////////////////////////////////////////// // "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 binder1and2and3of3(f,a1,a2,a3); } template typename Sig::ResultType operator()( const Ternary& f, const A1& a1, const A2& a2 ) const { return binder1and2of3(f,a1,a2); } template typename Sig::ResultType operator()( const Ternary& f, const A1& a1 ) const { return binder1of3(f,a1); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Curry3 curry3; FCPP_MAYBE_NAMESPACE_CLOSE 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 binder1and2of2(f,a1,a2); } template typename Sig::ResultType operator()( const Binary& f, const A1& a1 ) const { return binder1of2(f,a1); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Curry2 curry2; FCPP_MAYBE_NAMESPACE_CLOSE struct Curry1 { template struct Sig : public FunType > {}; template typename Sig::ResultType operator()( const Unary& f, const A1& a1 ) const { return binder1of1(f,a1); } }; FCPP_MAYBE_NAMESPACE_OPEN FCPP_MAYBE_EXTERN Curry1 curry1, curry; // "curry" is the same as "curry1" FCPP_MAYBE_NAMESPACE_CLOSE ////////////////////////////////////////////////////////////////////// // Finally, Curryable3 (what a huge beast) ////////////////////////////////////////////////////////////////////// template struct Curryable3Helper { R operator()( const F& f, const X& x, const Y& y, const Z& z ) const { return f(x,y,z); } }; template struct Curryable3Helper { R operator()( const F& f, const X& x, const AutoCurryType&, const AutoCurryType& ) const { return bind1of3(f,x); } }; template struct Curryable3Helper { R operator()( const F& f, const AutoCurryType&, const Y& y, const AutoCurryType& ) const { return bind2of3(f,y); } }; template struct Curryable3Helper { R operator()( const F& f, const AutoCurryType&, const AutoCurryType&, const Z& z ) const { return bind3of3(f,z); } }; template struct Curryable3Helper { R operator()( const F& f, const AutoCurryType&, const Y& y, const Z& z ) const { return binder2and3of3(f,y,z); } }; template struct Curryable3Helper { R operator()( const F& f, const X& x, const AutoCurryType&, const Z& z ) const { return binder1and3of3(f,x,z); } }; template struct Curryable3Helper { R operator()( const F& f, const X& x, const Y& y, const AutoCurryType& ) const { return binder1and2of3(f,x,y); } }; template struct Curryable3Helper2 { R operator()( const F& f, const X& x, const Y& y ) const { return binder1and2of3(f,x,y); } }; template struct Curryable3Helper2 { R operator()( const F& f, const AutoCurryType&, const Y& y ) const { return makeCurryable2(binder2of3(f,y)); } }; template struct Curryable3Helper2 { R operator()( const F& f, const X& x, const AutoCurryType& ) const { return makeCurryable2(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>()(f,x,y); } template typename Sig::ResultType operator()( const X& x ) const { return makeCurryable2(binder1of3(f,x)); } template 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>()(f,x,y,z); } }; template Curryable3 makeCurryable3( const F& f ) { return Curryable3( f ); } } // end namespace fcpp #endif