
On Tue, Jul 1, 2008 at 6:22 PM, Giovanni Piero Deretta <gpderetta@gmail.com> wrote:
On Tue, Jul 1, 2008 at 7:12 AM, Dean Michael Berris <mikhailberis@gmail.com> wrote:
I think the point of using expression templates is to be able to do something like:
copy( range(source) | taken(10) | map(mapper()), make_function_output_iterator(reducer()) // should have a better name? );
You do not need anything more than what is in Lambda/Phoenix here. Instead of having a different function for piping an generating views, you use the same function and curry it:
auto reduced = source | take(_, 10) | map(_, mapper()) | fold(_, reducer()) ;
the _ is like _1 in bind/lambda/phoenix, but it doesn't make the whole expression a lambda expression (it stops at one level). The pipe in practice works like a compose operator. If you put the range at the end, you wouldn't even need the '_' (just provide one less argument, hey it is haskell :) ), but you give up variadic (or overloaded) functions.
Isn't the whole point of creating an expression template based-approach to create these (maybe using proto I guess) and allow: 1. The same placeholders used in Phoenix+Proto to be used in the pipe syntax in range_ex (or an imaginary new RangeEx implementation). 2. Allow for efficient (i.e., compiler optimized/assisted) implementations of the composition of these new views/ranges/iterators. ? Although I do like how this looks granted that you are using C++0x's auto -- in today's C++, the reason I used the STL was to avoid having to compute the actual type produced by the pipe syntax. Maybe this is why Dave is asking for a better BOOST_TYPEOF. ;-)
I think that the basic ranges that should (at least) be supported are:
- mapped_range - filtered_range - taken_range (i.e. just the first n elements of a range) - taken_while_range (i.e. the first elements such as a predicate is true) - zipped_range - unfold_range (with which you can pretty much express any other range, see http://tinyurl.com/5mus25)
An eventual 'drop' (take all the elements after the first n) and 'drop_while' (drop the first elements such as a predicate is true) probably need strict evaluation anyway and aren't worth supporting explicitly.
I also think there should be a zipped_function which:
- takes N function objects and an N-tuple - applies each function to the appropriate tuple - returns a tuple of results
D'oh, of course, forgot this. I think that zipped_range on top of zipped_iterator is enough, you get the other functionality by composing with transformed_iterator.
Okay, but shouldn't this composition with transform_iterator be done with something that 'comes out of the box'?
<snip>
[2] I think that this is quite similar to the deforestation technique used by functional languages compilers. (see the wikipedia page and the linked articles). In FP it is used mostly to eliminate intermediate (lazily evaluated) lists, but the same technique can be applied in c++. In fact the rewrite rules used map perfectly to c++ templates.
Here I think you need the zipped_function idiom where you can create an 'in-step' function that can deal with tuples of inputs.
zipped_function(zipped_input) -> zipped_output
Another thing that's missing is a way to transform tuples of one form into another -- possibly ignoring tuple elements. I've posted a possible implementation based on Fusion's at_c, which allows:
map<int, string> source; // populate source.. for_each(source.begin(), source.end(), select<1> | (cout << arg1 << endl) //using fusion ); // select will choose the second element of the pair
Ok, but this is beyond boost range. I think that fusion svn already provides function objects for every algorithm/accessors, so this would becomes
for_each(source | map(_, select<1>() ) , coust << arg1 << endl )
BTW I call select<1>() simply first (and of course also have second, third, etc...).
Ok. I'd love to see Phoenix 2.0 come out and 'just work' with Boost.Range/RangeEx/Iterator/Algorithms -- I think now I "get" what Dave is looking for. :D -- Dean Michael C. Berris Software Engineer, Friendster, Inc.