Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Customization Points and Polymorphism Functional Programming Boost.Lambda 5/9/2017 1 Functional Programming A paradigm for computing with functions Not Procedural/Imperative Based on Lambda Calculus Avoids data mutation Often, resulting code is Alonzo Church Concise (terse) Efficient (inlining, static dispatch, return val. opt.) Robust (multithreading, no side effects) 5/9/2017 copyright 2006 David Abrahams, Eric Niebler 2 Lambda Calculus In-line anonymous function definition λ(x, y).x+y λ(x, y) { return x + y; } Typing template<class X, class Y, class R> R λ(X & x, Y & y) { return x + y; } Return value type deduction is hard! 5/9/2017 copyright 2006 David Abrahams, Eric Niebler 3 STL and the Functional Paradigm Remember this? // For each int i in s, print i * 3: std::transform( s.begin(), s.end(), std::ostream_iterator<int>(std::cout, " "), std::bind2nd(std::multiplies<int>(), 3) ); Pros Efficient Idiomatic 5/9/2017 Cons Hard to write Hard to read copyright 2006 David Abrahams, Eric Niebler 4 Lambda Functions Using Boost.Lambda // For each int i in s, print i * 3: std::for_each( s.begin(), s.end(), std::cout << ( _1 * 3 ) << " " ); Boost.Lambda helps STL deliver on the promises of Functional Programming 5/9/2017 copyright 2006 David Abrahams, Eric Niebler 5 Lambda in C++ std::cout << ( _1 * 3 ) << " “ λ _1 + _2 λ (_1) { std::cout << _1 * 3 << “ ”; } (_1, _2) { return _1 + _2; } Evaluation int x = 10, y = 20; Plus node (_1 + _2) (x, y); Placeholder _1 Placeholder _2 Gotcha: (++_1) (10); cannot take non-const r-values 5/9/2017 copyright 2006 David Abrahams, Eric Niebler 6 Higher-Order Functions Higher-order Function A function that takes a function as an argument, and/or returns a function. Currying Binding a function to some of its arguments. Example, using Boost.Bind std::tr1:: boost::bind(std::plus<int>(), 42, _1) (int) intint (int, int) 5/9/2017 copyright 2006 David Abrahams, Eric Niebler 7 Bind Pseudocode int λ (int & x) { return std::plus<int>() (42, x); } 5/9/2017 copyright 2006 David Abrahams, Eric Niebler 8 Binding Member Functions Resize all strings in a vector<string>: with STL binders: std::for_each( s.begin(), s.end(), std::bind2nd( std::mem_fun_ref( &std::string::resize ), 2 ) ); with Boost.Bind: std::for_each( s.begin(), s.end(), boost::bind( &std::string::resize, _1, 2 ) ); With member function, boost::bind (&std::string::resize, _1, _2) the first argument is always “*this” : _1->resize (_2); 5/9/2017 copyright 2006 David Abrahams, Eric Niebler 9 Nested Binds Total risk calculation: float total = 0.0f; for (int i = 0; i < loans.size(); ++i) total += loans[i]->risk(years); With function pointer float addRisk (float riskSoFar, Loan * loan) { return riskSoFar + loan->risk (years); // years global } std::accumulate (loans.begin(), loans.end(), 0.0f, addRisk); With Boost.Bind: std::accumulate( loans.begin(), loans.end(), 0.0f, bind( std::plus<float>(), _1, bind( &loan::risk, _2, years ) ) ); 5/9/2017 copyright 2006 David Abrahams, Eric Niebler 10 Nested Binds, cont. With Boost.Lambda: using namespace boost::lambda; std::accumulate( loans.begin(), loans.end(), 0.0f, _1 + bind( &loan::risk, _2, years ) ) ); No need for std::plus<float> (return type deduction) Magic: the meaning of _2 in bind makes sense only in the context of the outer expression Warning: not always what one wants! 5/9/2017 copyright 2006 David Abrahams, Eric Niebler 11 Bind and Relational Operators Find a pair for which p.second == 42 std::vector< std::pair<int, int> > v; std::find_if( v.begin(), v.end(), 42 == std::tr1::bind( &std::pair<int, int>::second, _1 ) ); What is special about the relational operators that lets Boost.Bind horn in on Boost.Lambda’s territory like this? 5/9/2017 copyright 2006 David Abrahams, Eric Niebler 12 Introducing Boost.Function Dynamically polymorphic function object Usage: Wraps anything callable that accepts A1, A2, … An and whose result can be converted to R For example: boost::function< R ( A1, A2, … An ) > typedef boost::function<int (int, int)> func; func f0( &std::min<int> ); // function pointer func f1( std::less<int>() ); // function object func f2( std::less<long>() ); Templated implicit conversion erases type automagically! 5/9/2017 copyright 2006 David Abrahams, Eric Niebler 13 Bind and Boost.Function Problem: how to save a curried function? ??????????????????????? add42 = bind( std::plus<int>(), 42, _1 ); boost::function<int(int)> cout << add42( 1 ) << endl; // prints "43" boost::_bi::bind_t< boost::_bi::unspecified , std::plus<int> , boost::_bi::list2<boost::_bi::value<int> Boost.Function can also save , boost::arg<1> > > Lambdas! add42 = 42 + boost::lambda::_1; cout << add42( 2 ) << endl; // prints "44" 5/9/2017 copyright 2006 David Abrahams, Eric Niebler 14 Other uses for Boost.Function Decoupling components powerful and stable APIs Generic callbacks, eg.: Boost.Threads Boost.Signals Ad hoc polymorphism The benefits of OO without the goop 5/9/2017 copyright 2006 David Abrahams, Eric Niebler 15 Lambda and Member Syntax bind() syntax isn’t always ideal int sum_second( vector< pair<int,int> * > const & v ) { return std::accumulate( v.begin(), v.end(), 0, _1 + bind( &pair<int,int>::second, _2 ) ); } Wouldn’t this be better? int sum_second( vector< pair<int,int> * > const & v ) { return std::accumulate( v.begin(), v.end(), 0, -> second ) _1 + _2 ->* &pair<int,int>::second // SYNTAX ERROR! ); // OK! } 5/9/2017 copyright 2006 David Abrahams, Eric Niebler 16 A Lambda Gotcha! What’s wrong with this? void display_ints( vector< int > const & v ) { std::for_each( v.begin(), v.end(), std::cout << '+' << _1 ); Displays: "+1234" } Deferring evaluation void display_ints( vector< int > const & v ) { std::for_each( v.begin(), v.end(), std::cout << constant('+') << _1 ); Displays: "+1+2+3+4" } 5/9/2017 copyright 2006 David Abrahams, Eric Niebler 17 Assignment in Lambdas Closure A function bound to a lexical scope C++ doesn’t have them Achieving closure with Boost.Lambda template< class It > int LL_distance( It begin, It end ) { int i = 0; 1var(i) std::for_each( begin, end, i++var(i) var(i) =i+ += constant(1) =constant(1) i ); ); + constant(1) + 1););); ); return i; Error! Not aOK! lambda! Wrong! Also, Can’t Evaluates assign OK! as lambda "i = 0to+ int! 1" } 5/9/2017 copyright 2006 David Abrahams, Eric Niebler 18 Advanced Lambdas A Boost.Lambda for loop: int a[5][10]; int i; std::for_each( a, a+5, for_( var(i) = 0, var(i) < 10, ++var(i) ) [ _1[ var(i) ] += 1 ] ); Initialization Condition Increment Loop body Some other Boost.Lambda control structures: if_(condition)[then_part] if_(condition)[then_part].else_[else_part] while_(condition)[body] do_[body].while_(condition) 5/9/2017 copyright 2006 David Abrahams, Eric Niebler 19 Guarding Against Nested Binds // F is a unary function // bar is a binary function template< class F > int bar( int, int ); void nested( const F & f ) { // Curry bar into unary function int x; nested( bind( bar, 1, _1 ) ); ... bind( f, unlambda(f), _1 )(x); _1 )(x); bind (bind(bar, 1, _1), _1) (x); } unlambda() ensures that a function Oops! “f” is a nestedobject bind! that happens to be a bind() is not treated magically. 5/9/2017 copyright 2006 David Abrahams, Eric Niebler 20 In a Bind Think functional Use Boost.Bind for currying and simple predicates Use Boost.Lambda when you want infix operators and control structures Use Boost.Function to store Binds and Lambdas and define powerful APIs Bind and Function are coming soon to a standard library near you! 5/9/2017 copyright 2006 David Abrahams, Eric Niebler 21