//////////////////////////////////////////////////////////////////////////// // lazy prelude.hpp // // Build lazy operations for Phoenix equivalents for FC++ // // These are equivalents of the Boost FC++ functoids in prelude.hpp // // Usage: All of these are functors which need various numbers of arguments. // Those can be supplied as real arguments or as Phoenix arguments. // Execution will happen when all the arguments are supplied. // e.g. // take(2,list)() or take(2,arg1)(list) // // Implemented so far: // // id (moved back to operators.hpp) // // A lot of what comes here uses the list type, so that will be needed first. // // Now that list is available I can start to build things here. // // // until(pred,f,start) - if pred(start) is true, return start // apply value = f(start) // apply value = f(value) // until pred(value) is true // return value // // The predicate argument pred must be a lazy function taking one argument // and returning bool. // This can be a lazy function with an argument already. // This has to be declared before the call to until. // The type can be declated using Predicate as in this example: // // Predicate::type f(greater(arg1,10)); // std::cout << until(f, inc, 1)() << std::endl; // // until2(pred,f,start,value2) - if pred(start,value2) is true, return start // apply value1 = f(start) // apply value1 = f(value1) // until pred(value1,value2) is true // return value1 // // NOTE: until2 has been defined because this code does not support // FC++ currying, so that a partial function cannot be passed // as an argument. This provides a way of passing a second parameter. // There is now the option to use Predicate as shown above. // // odd(n) true if n is odd // even(n) true if n is even // // last(list) // all_but_last(list) // at(list,n) // length(list) // filter(pred,list) // iterate(function,value) // repeat(value) // take(n,list) // drop(n,list) // enum_from(x) // enum_from_to(x,y) // //////////////////////////////////////////////////////////////////////////// // Interdependence: // The old Boost FC++ has a set of headers which interelate and call each // other in a complicated way. I am going to document the interdependence // of the files here. I will then make sure that they are called correctly // starting from this file. John Fletcher. February 2015. //////////////////////////////////////////////////////////////////////////// // BoostFC++ header sequence: // // prelude.hpp -> list.hpp (optinally monad.hpp at end) // list.hpp -> reuse.hpp // reuse.hpp -> function.hpp // function.hpp -> ref_count.hpp operator.hpp // ref_count.hpp -> config.hpp boost headers and RefCountType definition // operator.hpp -> lambda.hpp // lambda.hpp -> full.hpp (use of lambda internals is optional) // full.hpp -> smart.hpp curry.hpp pre_lambda.hpp (optionally full4.hpp) // smart.hpp -> signature.hpp // curry.hpp -> signature.hpp // signature.hpp -> config.hpp // //////////////////////////////////////////////////////////////////////////// // Proposed order in lazy_prelude.hpp // on the basis that files need what they call. // // lazy_config.hpp (If needed)* probably not needed. // lazy_signature.hpp (If needed)* // lazy_smart.hpp (If needed)* // lazy_curry.hpp (If needed)* // lazy_full.hpp (If needed)* // lazy_operator.hpp (absorb definition of RefCountType) // lazy_function.hpp (may not now be needed) // lazy_reuse.hpp (implemented without use of FC++ functions) // lazy_list.hpp // // * file does not yet exist. //////////////////////////////////////////////////////////////////////////// // This is implemented such that no other lazy_ file calls other lazy_ files. // They do call their own external files, which may well be duplicates. // That can be sorted out later. //////////////////////////////////////////////////////////////////////////// // Notes: full and curry operations should be covered by Phoenix. // The lambda operations are quite different from Phoenix lambda // and will be omitted. // The implementation monad can be postponed. // Some of function and reuse are needed for the list type. // I will review later whether they are part of the external interface. // // John Fletcher February 2015. //////////////////////////////////////////////////////////////////////////// /*============================================================================= Copyright (c) 2000-2003 Brian McNamara and Yannis Smaragdakis Copyright (c) 2001-2007 Joel de Guzman Copyright (c) 2015 John Fletcher Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ==============================================================================*/ #ifndef BOOST_PHOENIX_FUNCTION_LAZY_PRELUDE #define BOOST_PHOENIX_FUNCTION_LAZY_PRELUDE #include #include #include #include #include #include #include #include #include //////////////////////////////////////////////////////////////////////////// // To come here, the Haskell Prelude things which need list. // Things which do not need list are in lazy_operator.hpp. //////////////////////////////////////////////////////////////////////////// namespace boost { namespace phoenix { // These are in fcpp namespace as they introduce an FC++ style. namespace fcpp { template struct Predicate { typedef typename boost::function1 fun1_bool_T; typedef typename boost::phoenix::function bool_F_T; typedef bool_F_T type; }; template struct Function0 { typedef typename boost::function0 fun0_R; typedef typename boost::phoenix::function R_F; typedef R_F type; }; template struct Function1 { typedef typename boost::function1 fun1_R_A0; typedef typename boost::phoenix::function R_F_A0; typedef R_F_A0 type; }; template struct Function2 { typedef typename boost::function2 fun2_R_A0_A1; typedef typename boost::phoenix::function R_F_A0_A1; typedef R_F_A0_A1 type; }; } namespace impl { using fcpp::INV; using fcpp::VAR; using fcpp::reuser1; using fcpp::reuser2; using fcpp::reuser3; using boost::phoenix::arg_names::arg1; struct Pow { template struct result; template struct result : boost::remove_reference {}; template A0 operator()(N n, const A0 & a0, reuser2 r = NIL ) const { if ( n <= 0 ) return A0(1); else if ( n==1 ) return a0; else { A0 a1 = r( Pow(), n-1, a0)(); return a0*a1; } } }; struct Apply { template struct result; template struct result : boost::remove_reference {}; template A0 operator()(N n, const F &f, const A0 & a0, reuser3 r = NIL ) const { if ( n <= 0 ) return a0; else if ( n==1 ) return f(arg1)(a0); else { A0 a1 = r( Apply(), n-1, f, a0)(); return f(a1)(); } } }; struct Odd { template struct result; template struct result { typedef bool type; }; template typename result::type operator()( const T& x ) const { return x%2==1; } }; struct Even { template struct result; template struct result { typedef bool type; }; template typename result::type operator()( const T& x ) const { return x%2==0; } }; } typedef boost::phoenix::function Pow; typedef boost::phoenix::function Apply; typedef boost::phoenix::function Odd; typedef boost::phoenix::function Even; Pow pow; Apply apply; Odd odd; Even even; namespace impl { using fcpp::INV; using fcpp::VAR; using fcpp::reuser1; using fcpp::reuser2; using fcpp::reuser3; using boost::phoenix::arg_names::arg1; // I cannot yet do currying to pass e.g. greater(9,arg1) // as a function. This can be done using Predicate::type. struct Until { template struct result; template struct result : boost::remove_reference {}; template T operator()( const Pred& p,const Unary& op,const T &start) const { T tmp = start; while( !p(tmp)() ) { tmp = apply(1,op,tmp)(); } return tmp; } }; struct Until2 { template struct result; template struct result : boost::remove_reference {}; template typename result::type operator()( const Binary& p, const Unary& op, const T & start, const X & check ) const { T tmp1 = start; T tmp2; while( !p(tmp1,check)() ) { tmp2 = apply(1,op,tmp1)(); tmp1 = tmp2; } return tmp1; } }; struct Last { template struct result; template struct result { typedef typename result_of::ListType::value_type type; }; template typename result::type operator()( const L& ll ) const { size_t x = 0; typename result_of::ListType::delay_result_type l = delay(ll); while( !null( tail(l)() )() ) { l = tail(l)(); ++x; #ifndef BOOST_PHOENIX_NO_LAZY_EXCEPTIONS if (x > BOOST_PHOENIX_FUNCTION_MAX_LAZY_LIST_LENGTH) break; #endif } #ifndef BOOST_PHOENIX_NO_LAZY_EXCEPTIONS if (x > BOOST_PHOENIX_FUNCTION_MAX_LAZY_LIST_LENGTH) throw lazy_exception("Your list is too long!!"); #endif return head(l)(); } }; struct Init { template struct result; template struct result { typedef typename result_of::ListType::force_result_type type; }; template typename result::type operator()( const L& l, reuser1::delay_result_type> r = NIL ) const { if( null( tail( l )() )() ) return NIL; else return cons( head(l)(), r( Init(), tail(l)() )() )(); } }; struct Length { template struct result; template struct result { typedef size_t type; }; template size_t operator()( const L& ll ) const { typename L::delay_result_type l = delay(ll); size_t x = 0; while( !null(l)() ) { l = tail(l); ++x; if (x > BOOST_PHOENIX_FUNCTION_MAX_LAZY_LIST_LENGTH) break; } #ifndef BOOST_PHOENIX_NO_LAZY_EXCEPTIONS if (x > BOOST_PHOENIX_FUNCTION_MAX_LAZY_LIST_LENGTH) throw lazy_exception("Your list is too long!!"); #endif return x; } }; // at is Haskell's operator (!!) // This is zero indexed. at(l,0)() returns the first element. struct At { template struct result; template struct result { typedef typename result_of::ListType::value_type type; }; template typename result::type operator()( L l, size_t n ) const { while( n!=0 ) { l = tail(l); --n; } return head(l)(); } }; template struct FilterH { P p; L l; FilterH( const P& pp, const L& ll) : p(pp), l(ll) {} template struct result; template struct result { typedef typename boost::phoenix::result_of:: ListType::delay_result_type type; }; typename result::type operator()() const { typedef typename result_of::ListType:: delay_result_type result_type; typedef boost::function0 Fun2_R_P_L; typedef boost::phoenix::function FilterH_R_P_L; if (null(l)() ) return NIL; Fun2_R_P_L fun2_R_P_L = FilterH(p,tail(l)); FilterH_R_P_L filterh_R_P_L(fun2_R_P_L); if( p(head(l))() ) return cons( head(l)(), filterh_R_P_L() ); else return filterh_R_P_L(); } }; struct Filter { template struct result; template struct result { typedef typename result_of::ListType::delay_result_type type; }; template typename result::type operator()( const P& p, const L& ll) const { typename result_of::ListType::delay_result_type l = delay(ll); typedef typename result_of::ListType:: delay_result_type result_type; typedef boost::function0 Fun2_R_P_L; typedef boost::phoenix::function FilterH_R_P_L; Fun2_R_P_L fun2_R_P_L = FilterH(p,l); FilterH_R_P_L filterh_R_P_L(fun2_R_P_L); return filterh_R_P_L(); } }; template struct IterateH { F f; T t; IterateH( const F& ff, const T& tt) : f(ff), t(tt) {} template struct result; template struct result { typedef typename boost::remove_reference::type TT; typedef typename boost::remove_const::type TTT; typedef typename UseList::template List::type LType; typedef typename result_of::ListType:: delay_result_type type; }; typename result::type operator()() const { typedef typename UseList::template List::type LType; typedef typename result_of::ListType:: delay_result_type result_type; typedef boost::function0 Fun2_R_F_T; typedef boost::phoenix::function IterateH_R_F_T; Fun2_R_F_T fun2_R_F_T = IterateH(f,f(t)()); IterateH_R_F_T iterateh_R_F_T(fun2_R_F_T); return cons( t, iterateh_R_F_T() ); } }; struct Iterate { // Note: this does always return an odd_list; iterate() takes no ListLike // parameter, and it requires that its result be lazy. template struct result; template struct result { typedef typename boost::remove_reference::type TT; typedef typename boost::remove_const::type TTT; typedef typename UseList::template List::type LType; typedef typename result_of::ListType:: delay_result_type type; }; template typename result::type operator() (const F& f, const T& t) const { typedef typename UseList::template List::type LType; typedef typename result_of::ListType:: delay_result_type result_type; typedef boost::function0 Fun2_R_F_T; typedef boost::phoenix::function IterateH_R_F_T; Fun2_R_F_T fun2_R_F_T = IterateH(f,f(t)()); IterateH_R_F_T iterateh_R_F_T(fun2_R_F_T); return iterateh_R_F_T(); } }; } typedef boost::phoenix::function Until; typedef boost::phoenix::function Until2; typedef boost::phoenix::function Last; typedef boost::phoenix::function Init; typedef boost::phoenix::function Length; typedef boost::phoenix::function At; typedef boost::phoenix::function Filter; typedef boost::phoenix::function Iterate; Until until; Until2 until2; Last last; Init all_but_last; // renamed from init which is not available. Length length; At at_; //Renamed from at. Filter filter; Iterate iterate; namespace impl { struct Repeat { // See note for iterate() template struct result; template struct result { typedef typename boost::remove_reference::type TT; typedef typename boost::remove_const::type TTT; typedef typename UseList::template List::type LType; typedef typename result_of::ListType:: delay_result_type type; }; template typename result::type operator()( const T& x) const { return iterate(id,x); } }; struct Take { template struct result; template struct result { typedef typename result_of::ListType::force_result_type type; }; template typename result::type operator()( N n, const L& l, reuser2::force_result_type> r = NIL ) const { if( n <= 0 || null(l)() ) return NIL; else { return cons( head(l)(), r( Take(), n-1, tail(l)() )() )(); } } }; struct Drop { template struct result; template struct result { typedef typename result_of::ListType::delay_result_type type; }; template typename result::type operator()( size_t n, const L& ll ) const { typename L::delay_result_type l = delay(ll); while( n!=0 && !null(l)() ) { --n; l = tail(l)(); } return l; } }; template struct EFH { mutable T x; EFH( const T& xx) : x(xx) {} template struct result; template struct result { typedef typename boost::phoenix::UseList::template List::type LType; typedef typename boost::phoenix::result_of:: ListType::delay_result_type type; }; typename result::type operator()() const { typedef typename UseList::template List::type LType; typedef typename result_of::ListType:: delay_result_type result_type; typedef boost::function0 fun1_R_TTT; //std::cout << "EFH (" << x << ")" << std::endl; ++x; fun1_R_TTT efh_R_TTT = EFH(x); typedef boost::phoenix::function EFH_R_T; EFH_R_T efh_R_T(efh_R_TTT); #ifndef BOOST_PHOENIX_NO_LAZY_EXCEPTIONS if (x > BOOST_PHOENIX_FUNCTION_MAX_LAZY_LIST_LENGTH) throw lazy_exception("Running away in EFH!!"); #endif return cons( x-1, efh_R_T() ); } }; struct Enum_from { template struct result; template struct result { typedef typename boost::remove_reference::type TT; typedef typename boost::remove_const::type TTT; typedef typename UseList::template List::type LType; typedef typename result_of::ListType:: delay_result_type type; }; template typename result::type operator() (const T & x) const { typedef typename boost::remove_reference::type TT; typedef typename boost::remove_const::type TTT; typedef typename UseList::template List::type LType; typedef typename result_of::ListType:: delay_result_type result_type; typedef boost::function0 fun1_R_TTT; fun1_R_TTT efh_R_TTT = EFH(x); typedef boost::phoenix::function EFH_R_T; EFH_R_T efh_R_T(efh_R_TTT); //std::cout << "enum_from (" << x << ")" << std::endl; return efh_R_T(); } }; template struct EFTH { mutable T x; T y; EFTH( const T& xx, const T& yy) : x(xx), y(yy) {} template struct result; template struct result { typedef typename boost::phoenix::UseList::template List::type LType; typedef typename boost::phoenix::result_of:: ListType::delay_result_type type; }; typename result::type operator()() const { typedef typename UseList::template List::type LType; typedef typename result_of::ListType:: delay_result_type result_type; typedef boost::function0 fun1_R_TTT; //std::cout << "EFTH (" << x << ")" << std::endl; if (x > y ) return NIL; ++x; fun1_R_TTT efth_R_TTT = EFTH(x,y); typedef boost::phoenix::function EFTH_R_T; EFTH_R_T efth_R_T(efth_R_TTT); #ifndef BOOST_PHOENIX_NO_LAZY_EXCEPTIONS if (x > BOOST_PHOENIX_FUNCTION_MAX_LAZY_LIST_LENGTH) throw lazy_exception("Running away in EFTH!!"); #endif return cons( x-1, efth_R_T() ); } }; struct Enum_from_to { template struct result; template struct result { typedef typename boost::remove_reference::type TT; typedef typename boost::remove_const::type TTT; typedef typename UseList::template List::type LType; typedef typename result_of::ListType:: delay_result_type type; }; template typename result::type operator() (const T & x, const T & y) const { typedef typename boost::remove_reference::type TT; typedef typename boost::remove_const::type TTT; typedef typename UseList::template List::type LType; typedef typename result_of::ListType:: delay_result_type result_type; typedef boost::function0 fun1_R_TTT; fun1_R_TTT efth_R_TTT = EFTH(x,y); typedef boost::phoenix::function EFTH_R_T; EFTH_R_T efth_R_T(efth_R_TTT); //std::cout << "enum_from (" << x << ")" << std::endl; return efth_R_T(); } }; } //BOOST_PHOENIX_ADAPT_CALLABLE(apply, impl::apply, 3) // Functors to be used in reuser will have to be defined // using boost::phoenix::function directly // in order to be able to be used as arguments. typedef boost::phoenix::function Repeat; typedef boost::phoenix::function Take; typedef boost::phoenix::function Drop; typedef boost::phoenix::function Enum_from; typedef boost::phoenix::function Enum_from_to; Repeat repeat; Take take; Drop drop; Enum_from enum_from; Enum_from_to enum_from_to; namespace fcpp { } } } #endif