Translation of Ruby Code

I tried to use the Iterator module for this, but I’m missing something.
I assumed you had to make these iterators, but what’s the correct way to do this in Crystal?

squares  = Enumerator.new{ |y| (0..).each{ |n| y << 2**n}}
squares5 = Enumerator.new{ |y| (0..).each{ |n| y << 2**n * 5}}
 
pyth_quad = Enumerator.new do |y|
  n = squares.next
  m = squares5.next
  loop do
    if n < m
      y << n
      n = squares.next
    else
      y << m
      m = squares5.next
    end
  end
end

# this takes less than a millisecond
puts pyth_quad.take_while{ |n| n <= 1000000000}.join(" ")

This is what I came up with:

squares = (0..).each.map { |n| 2_i64**n }
squares5 = (0..).each.map { |n| 2_i64**n * 5 }

n = squares.next.as(Int)
m = squares5.next.as(Int)
pyth_quad = Iterator.of do
  if n < m
    value = n
    n = squares.next.as(Int)
  else
    value = m
    m = squares5.next.as(Int)
  end
  value
end

puts pyth_quad.take_while { |n| n <= 1000000000 }.join(" ")
3 Likes

Thank @asterite, as always.
The only thing I changed was the 2_i64 to 2_u64.

I got about 65-70% right, trying to following the examples in the docs.
I didn’t have the .map on the ends of (0..).each or the .as(Int) on the end of next, or moved m/n = squares/5... outside pyth_quad, or the .of on the end of Iterator.

I’m going to study it more, with the docs, to really understand what/why is going on.

FYI, here are time comparisons with different Ruby versions.
For Ruby ran as: $ time ruby pythquads.rb
For Crystal, compiled as: $ crystal build pythquads.cr --release
Ran as: $ time ./pythquads

Ruby 3.0.2              0.063 secs  
Ruby 2.7.4              0.057 secs
Truffleruby 21.2.0.1    0.037 secs
Crystal 1.1.1           0.007 secs
Crystal 1.2.1           0.002 secs
3 Likes

Ideally, the library or the compiler should be smarter about iterators that never finish, but that’s not the case right now. That’s why you need those as(Int) , because the return value of next could be Iterator::Stop.

I tried. To improve that but couldn’t. I’ll open an issue and see if someone can figure this out, or if it’s even worth it.

1 Like