Lazy Fibonacci Sequence in Ruby

2019-08-21 09:28发布

Coming from Python if I wanted to create an iterative lazy Fibonacci sequence, I could do something like this:

def fib():
    a = 1
    b = 2
    yield a
    yield b
    while True:
        yield a + b
        tmp = a
        a = b
        b = tmp + b

Grabbing next(fib) will give me the next element in the sequence by simply adding the previous two elements, so if I want to get the first 1000 Fibonacci elements, I can do that quickly:

fib = fib()
for i in range(0,1000):
    print(next(fib))  

If I try to reproduce that in Ruby with an Enumerator, it quickly chokes, recalculating the entire sequence each time we call fib.next():

def fib()
    Enumerator.new do |yielder|
        yielder << 1 << 2
        fib.lazy.zip(fib.lazy.drop(1)).each do |a,b|
            yielder << a + b
        end
    end
end  

I found another SO post on how to fix a recursive fibonacci with memoization in Ruby, but I am curious, are lazy sequences and generators a thing in Ruby?

1条回答
地球回转人心会变
2楼-- · 2019-08-21 10:10

Don't use recursive enumerators but do it like in Python? With a loop?

def fib()
  Enumerator.new do |yielder|
    a, b = 1, 2
    yielder << a << b
    loop do
      a, b = b, a + b
      yielder << b
    end
  end
end  

What you did there in Ruby looks in Python like this:

def fib():
    yield from (1, 2)
    for a, b in zip(fib(), islice(fib(), 1, None)):
        yield a + b

That's slow as well.

Btw, worse than the exponential time is the exponential amount of memory. That recursive Python version crashes for me when trying to compute the 32nd Fibonacci number. At that point I already have almost 4 million generators running. And your Ruby version crashes for me when trying to compute the 20th Fibonacci number, with error can't create fiber (FiberError). At that point I have almost 12000 fibers running.

查看更多
登录 后发表回答