/* FUNCTION-CLOSURE.hpp - metaprogramming tools for closing a function over given arguments Copyright (C) Lumiera.org 2009, Hermann Vosseler This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /** @file function-closure.hpp ** Partial function application and building a complete function closure. ** This is a small addendum to (and thin wrapper for) tr1/functional, supporting ** the case when a function should be closed over (partially or all) arguments, ** where especially the parameter values to close on are provided as a tuple. ** Additionally, we allow for composing (chaining) of two functions. ** ** Because we have to deal with arbitrary functions and arbitrary parameter types, ** we need a lot of repetitive code to "catch" functions from zero to nine arguments. ** At the bottom of this header, you'll find a function-style interface, which ** wraps up all these technicalities. ** ** @todo the implementation is able to handle partial application with N arguments, ** but currently we need just one argument, thus only this case was wrapped ** up into a convenient functions func::applyFirst and func::applyLast ** ** @see control::CommandDef usage example ** @see function.hpp ** @see tuple.hpp ** */ #ifndef LUMIERA_META_FUNCTION_CLOSURE_H #define LUMIERA_META_FUNCTION_CLOSURE_H #include "lib/meta/function.hpp" #include "lib/meta/tuple.hpp" #include namespace lumiera { namespace typelist{ namespace func { using std::tr1::function; namespace { // helpers for binding and applying a function to an argument tuple using tuple::element; template struct _Fun { typedef typename FunctionSignature >::Ret Ret; typedef typename FunctionSignature >::Args Args; }; template struct _Fun { typedef typename FunctionSignature >::Ret Ret; typedef typename FunctionSignature >::Args Args; }; template struct _Fun > { typedef typename FunctionSignature >::Ret Ret; typedef typename FunctionSignature >::Args Args; }; template struct is_Functor { static const bool value = false; }; template struct is_Functor > { static const bool value = true; }; /** * this Helper with repetitive specialisations for up to nine arguments * is used either to apply a function to arguments given as a tuple, or * to create the actual closure (functor) over all function arguments. */ template struct Apply; template<> //__________________________________ struct Apply<0> ///< Apply function without Arguments { template static RET invoke (FUN& f, TUP&) { return f (); } template static RET bind (FUN& f, TUP&) { return std::tr1::bind (f); } }; template<> //_________________________________ struct Apply<1> ///< Apply function with 1 Argument { template static RET invoke (FUN& f, TUP & arg) { return f (element<0>(arg)); } template static RET bind (FUN& f, TUP & arg) { return std::tr1::bind (f, element<0>(arg)); } }; template<> //_________________________________ struct Apply<2> ///< Apply function with 2 Arguments { template static RET invoke (FUN& f, TUP & arg) { return f ( element<0>(arg) , element<1>(arg) ); } template static RET bind (FUN& f, TUP & arg) { return std::tr1::bind (f, element<0>(arg) , element<1>(arg) ); } }; template<> //_________________________________ struct Apply<3> ///< Apply function with 3 Arguments { template static RET invoke (FUN& f, TUP & arg) { return f ( element<0>(arg) , element<1>(arg) , element<2>(arg) ); } template static RET bind (FUN& f, TUP & arg) { return std::tr1::bind (f, element<0>(arg) , element<1>(arg) , element<2>(arg) ); } }; template<> //_________________________________ struct Apply<4> ///< Apply function with 4 Arguments { template static RET invoke (FUN& f, TUP & arg) { return f ( element<0>(arg) , element<1>(arg) , element<2>(arg) , element<3>(arg) ); } template static RET bind (FUN& f, TUP & arg) { return std::tr1::bind (f, element<0>(arg) , element<1>(arg) , element<2>(arg) , element<3>(arg) ); } }; template<> //_________________________________ struct Apply<5> ///< Apply function with 5 Arguments { template static RET invoke (FUN& f, TUP & arg) { return f ( element<0>(arg) , element<1>(arg) , element<2>(arg) , element<3>(arg) , element<4>(arg) ); } template static RET bind (FUN& f, TUP & arg) { return std::tr1::bind (f, element<0>(arg) , element<1>(arg) , element<2>(arg) , element<3>(arg) , element<4>(arg) ); } }; template<> //_________________________________ struct Apply<6> ///< Apply function with 6 Arguments { template static RET invoke (FUN& f, TUP & arg) { return f ( element<0>(arg) , element<1>(arg) , element<2>(arg) , element<3>(arg) , element<4>(arg) , element<5>(arg) ); } template static RET bind (FUN& f, TUP & arg) { return std::tr1::bind (f, element<0>(arg) , element<1>(arg) , element<2>(arg) , element<3>(arg) , element<4>(arg) , element<5>(arg) ); } }; template<> //_________________________________ struct Apply<7> ///< Apply function with 7 Arguments { template static RET invoke (FUN& f, TUP & arg) { return f ( element<0>(arg) , element<1>(arg) , element<2>(arg) , element<3>(arg) , element<4>(arg) , element<5>(arg) , element<6>(arg) ); } template static RET bind (FUN& f, TUP & arg) { return std::tr1::bind (f, element<0>(arg) , element<1>(arg) , element<2>(arg) , element<3>(arg) , element<4>(arg) , element<5>(arg) , element<6>(arg) ); } }; template<> //_________________________________ struct Apply<8> ///< Apply function with 8 Arguments { template static RET invoke (FUN& f, TUP & arg) { return f ( element<0>(arg) , element<1>(arg) , element<2>(arg) , element<3>(arg) , element<4>(arg) , element<5>(arg) , element<6>(arg) , element<7>(arg) ); } template static RET bind (FUN& f, TUP & arg) { return std::tr1::bind (f, element<0>(arg) , element<1>(arg) , element<2>(arg) , element<3>(arg) , element<4>(arg) , element<5>(arg) , element<6>(arg) , element<7>(arg) ); } }; template<> //_________________________________ struct Apply<9> ///< Apply function with 9 Arguments { template static RET invoke (FUN& f, TUP & arg) { return f ( element<0>(arg) , element<1>(arg) , element<2>(arg) , element<3>(arg) , element<4>(arg) , element<5>(arg) , element<6>(arg) , element<7>(arg) , element<8>(arg) ); } template static RET bind (FUN& f, TUP & arg) { return std::tr1::bind (f, element<0>(arg) , element<1>(arg) , element<2>(arg) , element<3>(arg) , element<4>(arg) , element<5>(arg) , element<6>(arg) , element<7>(arg) , element<8>(arg) ); } }; /* ===== Helpers for partial function application ===== */ using std::tr1::_Placeholder; // what is the "official" way to import them? /** * Build a sequence of tr1 function argument placeholder types. * For each of the elements of the provided reference sequence, * a Placeholder is added, numbers counting up starting with 1 (!) */ template class PlaceholderTuple { typedef typename Tuple::Type TypeSeq; typedef typename Tuple::TailType TailSeq; typedef typename PlaceholderTuple::PlaceholderSeq TailPlaceholderSeq; public: typedef typename Prepend<_Placeholder, TailPlaceholderSeq>::Seq PlaceholderSeq; typedef Tuple Type; }; template struct PlaceholderTuple, i> : PlaceholderTuple {}; template struct PlaceholderTuple { typedef Types<> PlaceholderSeq; typedef Tuple > Type; }; } // (END) impl-namespace /* ======= core operations: closures and partial application ========= */ /** * Closure-creating template. * @note taking functor objects \em and parameters per reference */ template class TupleApplicator { typedef typename FunctionSignature< function >::Args Args; typedef typename FunctionSignature< function >::Ret Ret; typedef function BoundFunc; enum { ARG_CNT = count::value }; /** storing a ref to the parameter tuple */ Tuple& params_; public: TupleApplicator (Tuple& args) : params_(args) { } BoundFunc bind (SIG& f) { return Apply::template bind (f, params_); } BoundFunc bind (function const& f) { return Apply::template bind (f, params_); } Ret operator() (SIG& f) { return Apply::template invoke (f, params_); } Ret operator() (function& f) { return Apply::template invoke (f, params_); } }; /** * Closing a function over its arguments. * This is a small usage example or spin-off, * having almost the same effect than invoking tr1::bind. * The notable difference is that the function arguments for * creating the closure are passed in as one compound tuple. */ template class FunctionClosure { typedef typename func::_Fun::Args Args; typedef typename func::_Fun::Ret Ret; function closure_; public: FunctionClosure (SIG& f, Tuple& arg) : closure_(TupleApplicator(arg).bind(f)) { } FunctionClosure (function const& f, Tuple& arg) : closure_(TupleApplicator(arg).bind(f)) { } Ret operator() () { return closure_(); } typedef Ret result_type; ///< for STL use typedef void argument_type; }; /** * Partial function application * Takes a function and a value tuple, * using the latter to close function arguments * either from the front (left) or aligned to the end * of the function argument list. Result is a "reduced" function, * expecting only the remaining "un-closed" arguments at invocation. */ template class PApply { typedef typename _Fun::Args Args; typedef typename _Fun::Ret Ret; typedef typename Args::List ArgsList; typedef typename VAL::List ValList; enum { ARG_CNT = count::value , VAL_CNT = count ::value , ROFFSET = (VAL_CNT < ARG_CNT)? ARG_CNT-VAL_CNT : 0 }; // create list of the *remaining* arguments, after applying the ValList typedef typename Splice::Back LeftReduced; typedef typename Splice::Front RightReduced; // build a list, where each of the *remaining* arguments is replaced by a placeholder marker typedef typename func::PlaceholderTuple::PlaceholderSeq::List LeftPlaceholders; typedef typename func::PlaceholderTuple::PlaceholderSeq::List RightPlaceholders; // ... and splice these placeholders on top of the original argument type list, // thus retaining the types to be closed, but setting a placeholder for each remaining argument typedef typename Splice::List LeftReplaced; typedef typename Splice::List RightReplaced; typedef typename Tuple::Type ArgsL; typedef typename Tuple::Type ArgsR; // create a "builder" helper, which accepts exactly the value tuple elements // and puts them at the right location, while default-constructing the remaining // (=placeholder)-arguments. Using this builder helper, we can finally set up // the argument tuples (Left/RightReplacedArgs) used for the tr1::bind call typedef tuple::BuildTuple BuildL; typedef tuple::BuildTuple BuildR; /** Contains the argument values, starting from left. * Any remaining positions are occupied by binding placeholders */ typedef typename Tuple::TupleType LeftReplacedArgs; /** Contains the argument values, aligned to the end of the function argument list. * Any remaining positions before are occupied by binding placeholders */ typedef typename Tuple::TupleType RightReplacedArgs; public: typedef function::Sig> LeftReducedFunc; typedef function::Sig> RightReducedFunc; /** do a partial function application, closing the first arguments * f(a,b,c)->res + (a,b) yields f(c)->res * * @param f function, function pointer or functor * @param arg value tuple, used to close function arguments starting from left * @return new function object, holding copies of the values and using them at the * closed arguments; on invocation, only the remaining arguments need to be supplied. */ static LeftReducedFunc bindFront (SIG& f, Tuple const& arg) { LeftReplacedArgs params (BuildL::create(arg)); return func::Apply::template bind (f, params); } /** do a partial function application, closing the last arguments * f(a,b,c)->res + (b,c) yields f(a)->res * * @param f function, function pointer or functor * @param arg value tuple, used to close function arguments starting from right * @return new function object, holding copies of the values and using them at the * closed arguments; on invocation, only the remaining arguments need to be supplied. */ static RightReducedFunc bindBack (SIG& f, Tuple const& arg) { RightReplacedArgs params (BuildR::create(arg)); return func::Apply::template bind (f, params); } }; namespace _composed { // repetitive impl.code for function composition using std::tr1::bind; using std::tr1::placeholders::_1; using std::tr1::placeholders::_2; using std::tr1::placeholders::_3; using std::tr1::placeholders::_4; using std::tr1::placeholders::_5; using std::tr1::placeholders::_6; using std::tr1::placeholders::_7; using std::tr1::placeholders::_8; using std::tr1::placeholders::_9; template struct Build; template struct Build { static function func(F1& f1, F2& f2) { return bind (f2, bind (f1)); } }; template struct Build { static function func(F1& f1, F2& f2) { return bind (f2, bind (f1,_1)); } }; template struct Build { static function func(F1& f1, F2& f2) { return bind (f2, bind (f1,_1,_2)); } }; template struct Build { static function func(F1& f1, F2& f2) { return bind (f2, bind (f1,_1,_2,_3)); } }; template struct Build { static function func(F1& f1, F2& f2) { return bind (f2, bind (f1,_1,_2,_3,_4)); } }; template struct Build { static function func(F1& f1, F2& f2) { return bind (f2, bind (f1,_1,_2,_3,_4,_5)); } }; template struct Build { static function func(F1& f1, F2& f2) { return bind (f2, bind (f1,_1,_2,_3,_4,_5,_6)); } }; template struct Build { static function func(F1& f1, F2& f2) { return bind (f2, bind (f1,_1,_2,_3,_4,_5,_6,_7)); } }; template struct Build { static function func(F1& f1, F2& f2) { return bind (f2, bind (f1,_1,_2,_3,_4,_5,_6,_7,_8)); } }; template struct Build { static function func(F1& f1, F2& f2) { return bind (f2, bind (f1,_1,_2,_3,_4,_5,_6,_7,_8,_9)); } }; } // (End) impl namespace (_composed) /** * Functional composition. Create a functor, which * on invocation will execute two functions chained, * i.e. fed the result of invoking the first function * as argument into the second function. */ template class FunctionComposition { typedef typename func::_Fun::Args Args; typedef typename func::_Fun::Ret Ret1; typedef Types ArgsF2; typedef typename FunctionTypedef::Sig SigF2; typedef typename FunctionTypedef::Sig ChainedSig; enum { ARG_CNT = count::value }; public: static function chain (SIG1& f1, SigF2& f2) { return _composed::Build::func (f1,f2); } }; /** * Bind a specific argument to an arbitrary value. * Especially, this "value" might be another binder. */ template class BindToArgument { typedef typename _Fun::Args Args; typedef typename _Fun::Ret Ret; typedef typename Args::List ArgsList; typedef typename Types::List ValList; enum { ARG_CNT = count::value }; typedef typename Splice::Front RemainingFront; typedef typename Splice::Back RemainingBack; typedef typename func::PlaceholderTuple::PlaceholderSeq::List PlaceholdersBefore; typedef typename func::PlaceholderTuple::PlaceholderSeq::List PlaceholdersBehind; typedef typename Append::List ,PlaceholdersBehind >::List PreparedArgs; typedef typename Append::List ReducedArgs; typedef tuple::BuildTuple BuildPreparedArgs; typedef typename Tuple::TupleType PreparedArgTuple; public: typedef function::Sig> ReducedFunc; static ReducedFunc reduced (SIG& f, Tuple const& val) { PreparedArgTuple params (BuildPreparedArgs::create(val)); return func::Apply::template bind (f, params); } }; namespace { // ...helpers for specifying types in function declarations.... template struct _Sig { typedef typename FunctionTypedef::Sig Type; typedef TupleApplicator Applicator; }; template struct _Clo { typedef typename _Fun::Ret Ret; typedef typename _Sig::Type Signature; typedef FunctionClosure Type; }; template struct _Chain { typedef typename _Fun::Args Args; typedef typename _Fun::Ret Ret; typedef typename FunctionTypedef::Sig Chained; typedef function Function; }; template struct _PapS { typedef typename _Fun::Ret Ret; typedef typename _Fun::Args Args; typedef typename Split::Head Arg; typedef typename Split::Tail Rest; typedef typename _Sig::Type Signature; typedef function Function; }; template struct _PapE { typedef typename _Fun::Ret Ret; typedef typename _Fun::Args Args; typedef typename Split::End Arg; typedef typename Split::Prefix Rest; typedef typename _Sig::Type Signature; typedef function Function; }; } // (End) argument type shortcuts /* ========== function-style interface ============= */ /** build a TupleApplicator, which embodies the given * argument tuple and can be used to apply various * functions to them. */ template typename _Sig::Applicator tupleApplicator (Tuple& args) { typedef typename _Sig::Type Signature; return TupleApplicator (args); } /** apply the given function to the argument tuple */ template typename _Fun::Ret apply (SIG& f, Tuple& args) { typedef typename _Fun::Ret Ret; // typedef typename _Sig::Type Signature; // Note: deliberately re-building the Signature Type return TupleApplicator (args) (f); // in order to get better error messages here } /** close the given function over all arguments, * using the values from the argument tuple. * @return a closure object, which can be * invoked later to yield the * function result. */ template typename _Clo::Type closure (SIG& f, Tuple& args) { typedef typename _Fun::Ret Ret; typedef typename _Sig::Type Signature; typedef typename _Clo::Type Closure; return Closure (f,args); } /** close the given function over the first argument */ template typename _PapS::Function applyFirst (SIG& f, ARG arg) { typedef typename _PapS::Arg ArgType; typedef Types ArgTypeSeq; typedef Tuple ArgTuple; ArgTuple val(arg); return PApply::bindFront (f, val); } /** bind the last function argument to an arbitrary term, * which especially might be a (nested) binder... */ template typename _PapE::Function bindLast (SIG& f, TERM arg) { typedef Types ArgTypeSeq; typedef Tuple ArgTuple; ArgTuple argT(arg); const int LAST_POS = count::Args>::value; return BindToArgument::reduced (f, argT); } /** build a functor chaining the given functions */ template typename _Chain::Function chained (SIG1& f1, SIG2& f2) { typedef typename _Chain::Ret Ret; return FunctionComposition::chain (f1, f2); } }}} // namespace lumiera::typelist::func #endif