

Lazy sequences in idiomatic C++ using iterators - jzwinck
http://ideone.com/T1xVLz

======
pfultz2
This can already be done using Linq in C++, which is range-based rather than
iterator based:

    
    
        auto q = LINQ(
                    from(z, boost::irange(1, std::numerical_limits<int>::max()))
                    from(x, boost::irange(1, z))
                    from(y, boost::irange(1, x))
                    where(x*x + y*y == z*z)
                    select(boost::fusion::make_vector(x, y, z))
                );
        for(auto&& x:q | linq::take(10)) std::cout << x << std::endl;
    

Hopefully, once we get ranges in the C++ standard library, we can add list
comprehension to the language, perhaps something like this:

    
    
        auto q = [
                    for (z, std::irange(1, std::numerical_limits<int>::max()))
                    for (x, std::irange(1, z))
                    for (y, std::irange(1, x))
                    if (x*x + y*y == z*z)
                    boost::fusion::make_vector(x, y, z)
                ];
        for(auto&& x:q | std::take(10)) std::cout << x << std::endl;

------
zwegner
All those if statements inside loops... would be a lot cleaner (and faster!)
to just use a single goto statement:

    
    
      goto cont;
    
      for (; ; ++z)
        for (; x <= z; ++x)
          for (; y <= z; ++y) {
            if (x*x + y*y == z*z) return *this;
      cont:
          }

~~~
jzwinck
I totally agree--thank you for bringing this up. I'm not sure it would be
faster, but it is an interesting case for goto.

I saw another proposal referencing the original article which used a trio of
functions in a nice way to achieve something similar without the goto (and
without the ifs). My main point was to illustrate the use of custom iterators.

~~~
zwegner
Consider me nerd-sniped. I typed the last post on my phone, but just had to
bust out the laptop to check. Noticed a couple bugs I had: the for-loop
initializers need to be set, and there needs to be an empty statement after
the cont: label.

The goto version only has one unconditional branch outside of a loop, rather
than three conditional branches inside loops. Anyways, the speed difference
shouldn't be too big, as the branches are pretty predictable (pretty much
always not taken).

Quick benchmark of the original and mine, up to the first 3000 triples:

    
    
      $ c++ -O3 pyth1.cpp  && time ./a.out | md5
      33aa33d6cad59951489757e06aeb5a15
      
      real    0m5.492s
      user    0m5.484s
      sys     0m0.007s
      $ c++ -O3 pyth2.cpp  && time ./a.out | md5
      33aa33d6cad59951489757e06aeb5a15
      
      real    0m4.248s
      user    0m4.238s
      sys     0m0.011s

------
lelf
This is different. They are _combining_ streams in the original article.
(‘Start with the stream of integers from 1 to infinity <…>’).

Your code is

    
    
      take 10 mutable_spaghetti_function

~~~
dkhenry
And as a trade off you get a much cleaner and more performant solution to the
same contrived problem. This is where Haskell and functional coders tend to
break down. Yes its mutable, but by violating that one rule you gain so much
in terms of readability and performance.

~~~
cgh
You are right about more performant, but how is it cleaner and more readable
than this?

    
    
      pyth x = [(a,b,c) | a<-[1..x], b<-[1..x], c<-[1..x], (a^2)+(b^2) == (c^2)]

~~~
dkhenry
Thats not c++ code. My claim is that if you try to stay pure using C++ you end
up with very very ugly code that preforms pretty poorly.

------
detrino
A cleaner, more efficient version:
[http://ideone.com/B8p7m0](http://ideone.com/B8p7m0)

Edit: A better way to write the inner loop:
[http://ideone.com/wEfNyh](http://ideone.com/wEfNyh)

Edit: When the values are initialized to 3, 4, 5 instead of 0, 0, 0, the
program can be simplified to:
[http://ideone.com/oyNk1O](http://ideone.com/oyNk1O)

------
djeps
I'm learning C/C++, tried to compile
([http://ideone.com/T1xVLz](http://ideone.com/T1xVLz)) your code in ubuntu,
with gcc-4.8, and an error about copy_n is not declared in this scope was
raised.

error: ‘copy_n’ was not declared in this scope

what is the problem? Is it something to do with gcc-4.8 and shared libs?

Thanks

