1[/============================================================================== 2 Copyright (C) 2001-2010 Joel de Guzman 3 Copyright (C) 2001-2005 Dan Marsden 4 Copyright (C) 2001-2010 Thomas Heller 5 6 Distributed under the Boost Software License, Version 1.0. (See accompanying 7 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 8===============================================================================/] 9 10[section Scope] 11 12Up until now, the most basic ingredient is missing: creation of and access to 13local variables in the stack. When recursion comes into play, you will soon 14realize the need to have true local variables. It may seem that we do not need 15this at all since an unnamed lambda function cannot call itself anyway; at least 16not directly. With some sort of arrangement, situations will arise where a 17lambda function becomes recursive. A typical situation occurs when we store a 18lambda function in a [@http://www.boost.org/libs/function Boost.Function], 19essentially naming the unnamed lambda. 20 21There will also be situations where a lambda function gets passed as an argument 22to another function. This is a more common situation. In this case, the lambda 23function assumes a new scope; new arguments and possibly new local variables. 24 25This section deals with local variables and nested lambda scopes. 26 27[section Local Variables] 28 29 #include <boost/phoenix/scope/local_variable.hpp> 30 31We use an instance of: 32 33 expression::local_variable<Key>::type 34 35to represent a local variable. The local variable acts as an imaginary data-bin 36where a local, stack based data will be placed. `Key` is an arbitrary type that 37is used to identify the local variable. Example: 38 39 struct size_key; 40 expression::local_variable<size_key>::type size; 41 42[*Predefined Local Variables] 43 44There are a few predefined instances of `expression::local_variable<Key>::type` 45named `_a`..`_z` that you can already use. To make use of them, simply use the 46`namespace boost::phoenix::local_names`: 47 48 using namespace boost::phoenix::local_names; 49 50[endsect] 51[section let] 52 53 #include <boost/phoenix/scope/let.hpp> 54 55You declare local variables using the syntax: 56 57 let(local-declarations) 58 [ 59 let-body 60 ] 61 62`let` allows 1..N local variable declarations (where N == 63`BOOST_PHOENIX_LOCAL_LIMIT`). Each declaration follows the form: 64 65 local-id = lambda-expression 66 67[note You can set `BOOST_PHOENIX_LOCAL_LIMIT`, the predefined maximum local 68variable declarations in a let expression. By default, `BOOST_PHOENIX_LOCAL_LIMIT` is 69set to `BOOST_PHOENIX_LIMIT`.] 70 71Example: 72 73 let(_a = 123, _b = 456) 74 [ 75 _a + _b 76 ] 77 78[*Reference Preservation] 79 80The type of the local variable assumes the type of the lambda- expression. Type 81deduction is reference preserving. For example: 82 83 let(_a = arg1, _b = 456) 84 85`_a` assumes the type of `arg1`: a reference to an argument, while `_b` has type 86`int`. 87 88Consider this: 89 90 int i = 1; 91 92 let(_a = arg1) 93 [ 94 cout << --_a << ' ' 95 ] 96 (i); 97 98 cout << i << endl; 99 100the output of above is : 0 0 101 102While with this: 103 104 int i = 1; 105 106 let(_a = val(arg1)) 107 [ 108 cout << --_a << ' ' 109 ] 110 (i); 111 112 cout << i << endl; 113 114the output is : 0 1 115 116Reference preservation is necessary because we need to have L-value access to 117outer lambda-scopes (especially the arguments). `arg`s and `ref`s are L-values. 118`val`s are R-values. 119 120[*Visibility] 121[#phoenix.modules.scope.let.visibility] 122 123The scope and lifetimes of the local variables is limited within the let-body. 124`let` blocks can be nested. A local variable may hide an outer local variable. 125For example: 126 127 let(_x = _1, _y = _2) 128 [ 129 // _x here is an int: 1 130 131 let(_x = _3) // hides the outer _x 132 [ 133 cout << _x << _y // prints "Hello, World" 134 ] 135 ](1," World","Hello,"); 136 137The actual values of the parameters _1, _2 and _3 are supplied from the 138bracketed list at the end of the `let`. 139 140There is currently a limitation that the inner `let` cannot be supplied with a 141constant e.g. `let(_x = 1)`. 142 143The RHS (right hand side lambda-expression) of each local-declaration cannot 144refer to any LHS local-id. At this point, the local-ids are not in scope yet; 145they will only be in scope in the let-body. The code below is in error: 146 147 let( 148 _a = 1 149 , _b = _a // Error: _a is not in scope yet 150 ) 151 [ 152 // _a and _b's scope starts here 153 /*. body .*/ 154 ] 155 156However, if an outer let scope is available, this will be searched. Since 157the scope of the RHS of a local-declaration is the outer scope enclosing 158the let, the RHS of a local-declaration can refer to a local variable of 159an outer scope: 160 161 let(_a = 1) 162 [ 163 let( 164 _a = _1 165 , _b = _a // Ok. _a refers to the outer _a 166 ) 167 [ 168 /*. body .*/ 169 ] 170 ](1) 171 172[endsect] 173[section lambda] 174 175 #include <boost/phoenix/scope/lambda.hpp> 176 177A lot of times, you'd want to write a lazy function that accepts one or more 178functions (higher order functions). STL algorithms come to mind, for example. 179Consider a lazy version of `stl::for_each`: 180 181 struct for_each_impl 182 { 183 template <typename C, typename F> 184 struct result 185 { 186 typedef void type; 187 }; 188 189 template <typename C, typename F> 190 void operator()(C& c, F f) const 191 { 192 std::for_each(c.begin(), c.end(), f); 193 } 194 }; 195 196 function<for_each_impl> const for_each = for_each_impl(); 197 198Notice that the function accepts another function, `f` as an argument. The scope 199of this function, `f`, is limited within the `operator()`. When `f` is called 200inside `std::for_each`, it exists in a new scope, along with new arguments and, 201possibly, local variables. This new scope is not at all related to the outer 202scopes beyond the `operator()`. 203 204Simple syntax: 205 206 lambda 207 [ 208 lambda-body 209 ] 210 211Like `let`, local variables may be declared, allowing 1..N local variable 212declarations (where N == `BOOST_PHOENIX_LOCAL_LIMIT`): 213 214 lambda(local-declarations) 215 [ 216 lambda-body 217 ] 218 219The same restrictions apply with regard to scope and visibility. The RHS 220(right hand side lambda-expression) of each local-declaration cannot refer 221to any LHS local-id. The local-ids are not in scope yet; they will be in 222scope only in the lambda-body: 223 224 lambda( 225 _a = 1 226 , _b = _a // Error: _a is not in scope yet 227 ) 228 229See [link phoenix.modules.scope.let.visibility `let` Visibility] for more information. 230 231Example: Using our lazy `for_each` let's print all the elements in a container: 232 233 for_each(arg1, lambda[cout << arg1]) 234 235As far as the arguments are concerned (arg1..argN), the scope in which the 236lambda-body exists is totally new. The left `arg1` refers to the argument passed 237to `for_each` (a container). The right `arg1` refers to the argument passed by 238`std::for_each` when we finally get to call `operator()` in our `for_each_impl` 239above (a container element). 240 241Yet, we may wish to get information from outer scopes. While we do not have 242access to arguments in outer scopes, what we still have is access to local 243variables from outer scopes. We may only be able to pass argument related 244information from outer `lambda` scopes through the local variables. 245 246[note This is a crucial difference between `let` and `lambda`: `let` 247does not introduce new arguments; `lambda` does.] 248 249Another example: Using our lazy `for_each`, and a lazy `push_back`: 250 251 struct push_back_impl 252 { 253 template <typename C, typename T> 254 struct result 255 { 256 typedef void type; 257 }; 258 259 template <typename C, typename T> 260 void operator()(C& c, T& x) const 261 { 262 c.push_back(x); 263 } 264 }; 265 266 function<push_back_impl> const push_back = push_back_impl(); 267 268write a lambda expression that accepts: 269 270# a 2-dimensional container (e.g. `vector<vector<int> >`) 271# a container element (e.g. `int`) 272 273and pushes-back the element to each of the `vector<int>`. 274 275Solution: 276 277 for_each(arg1, 278 lambda(_a = arg2) 279 [ 280 push_back(arg1, _a) 281 ] 282 ) 283 284Since we do not have access to the arguments of the outer scopes beyond the 285lambda-body, we introduce a local variable `_a` that captures the second outer 286argument: `arg2`. Hence: _a = arg2. This local variable is visible inside the 287lambda scope. 288 289(See [@../../example/lambda.cpp lambda.cpp]) 290 291[endsect] 292 293[endsect] 294