[Ruby] 無限フィボナッチ

# 無限フィボナッチ

Yo! クリぼっちでも [フィボナッチ](https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A3%E3%83%9C%E3%83%8A%E3%83%83%E3%83%81%E6%95%B0)！ :sunglasses:

## 旧コード

大好きな DelegateClass と Enumerator を組み合わせて書いてみた。後で書き直しました (後述) 。

```rb
class FibonacciNumbers < DelegateClass(Enumerator)
  def initialize
    super(fibonacci_numbers)
  end

  private

  def fibonacci_numbers
    Enumerator.new do |y|
      memo = [0, 1]
  
      loop.with_index do |_, i|
        if i < 2
          y << memo[i]
        else
          memo = memo[1], memo.sum
          y << memo[1]
        end
      end
    end
  end
end

fibonacci_numbers = FibonacciNumbers.new
fibonacci_numbers.first(10) #=> [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
fibonacci_numbers.first(10_000).last #=> 20793608237133498072112648988642836825087036094015903119682945866528501423455686648927456034305226515591757343297190158010624794267250973176133810179902738038231789748346235556483191431591924532394420028067810320408724414693462849062668387083308048250920654493340878733226377580847446324873797603734794648258113858631550404081017260381202919943892370942852601647398213554479081823593715429566945149312993664846779090437799284773675379284270660175134664833266377698642012106891355791141872776934080803504956794094648292880566056364718187662668970758537383352677420835574155945658542003634765324541006121012446785689171494803262408602693091211601973938229446636049901531963286159699077880427720289235539329671877182915643419079186525118678856821600897520171070499437657067342400871083908811800976259727431820539554256869460815355918458253398234382360435762759823179896116748424269545924633204614137992850814352018738480923581553988990897151469406131695614497783720743461373756218685106856826090696339815490921253714537241866911604250597353747823733268178182198509240226955826416016690084749816072843582488613184829905383150180047844353751554201573833105521980998123833253261228689824051777846588461079790807828367132384798451794011076569057522158680378961532160858387223882974380483931929541222100800313580688585002598879566463221427820448492565073106595808837401648996423563386109782045634122467872921845606409174360635618216883812562321664442822952537577492715365321134204530686742435454505103269768144370118494906390254934942358904031509877369722437053383165360388595116980245927935225901537634925654872380877183008301074569444002426436414756905094535072804764684492105680024739914490555904391369218696387092918189246157103450387050229300603241611410707453960080170928277951834763216705242485820801423866526633816082921442883095463259080471819329201710147828025221385656340207489796317663278872207607791034431700112753558813478888727503825389066823098683355695718137867882982111710796422706778536913192342733364556727928018953989153106047379741280794091639429908796650294603536651238230626
```

なお

```rb
def fibonacci_numbers
  memo = [0, 1]

  Enumerator.new do |y|
    # 略
  end
end
```

と、ローカル変数 `memo` の代入を Enumerator.new のブロックの外で行うと挙動が変わってしまうので注意。

```rb
# Enumerator.new のブロックがクロージャとしてローカル変数 memo の状態を保持してしまう。
# そのせいで first に 3 以上の整数を渡して呼び出すと、つど結果が変わってしまう。
fibonacci_numbers.first(3) #=> [0, 1, 1]
fibonacci_numbers.first(3) #=> [1, 1, 2]
fibonacci_numbers.first(3) #=> [1, 2, 3]
```

## 新コード

@kts_h さんのコメントを参考 (というかほぼそのままですが……) にして、以下の方針でよりシンプルなコードにしました。

* オブジェクトを生成せずに FibonacciNumbers の Module 自体に機能をもたせる。
* 他のオブジェクトに委譲するのではなく FibonacciNumbers 自体を Enumerable にする。
* loop メソッドのブロック内の if 式を取り除く。

```rb
module FibonacciNumbers
  extend Enumerable

  def self.each
    return enum_for unless block_given?
    
    a, b = 0, 1
    loop do
      yield a
      a, b = b, a + b
    end
  end
end

FibonacciNumbers.first(10) #=> [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
FibonacciNumbers.first(10_000).last #=> 20793608237133498072112648988642836825087036094015903119682945866528501423455686648927456034305226515591757343297190158010624794267250973176133810179902738038231789748346235556483191431591924532394420028067810320408724414693462849062668387083308048250920654493340878733226377580847446324873797603734794648258113858631550404081017260381202919943892370942852601647398213554479081823593715429566945149312993664846779090437799284773675379284270660175134664833266377698642012106891355791141872776934080803504956794094648292880566056364718187662668970758537383352677420835574155945658542003634765324541006121012446785689171494803262408602693091211601973938229446636049901531963286159699077880427720289235539329671877182915643419079186525118678856821600897520171070499437657067342400871083908811800976259727431820539554256869460815355918458253398234382360435762759823179896116748424269545924633204614137992850814352018738480923581553988990897151469406131695614497783720743461373756218685106856826090696339815490921253714537241866911604250597353747823733268178182198509240226955826416016690084749816072843582488613184829905383150180047844353751554201573833105521980998123833253261228689824051777846588461079790807828367132384798451794011076569057522158680378961532160858387223882974380483931929541222100800313580688585002598879566463221427820448492565073106595808837401648996423563386109782045634122467872921845606409174360635618216883812562321664442822952537577492715365321134204530686742435454505103269768144370118494906390254934942358904031509877369722437053383165360388595116980245927935225901537634925654872380877183008301074569444002426436414756905094535072804764684492105680024739914490555904391369218696387092918189246157103450387050229300603241611410707453960080170928277951834763216705242485820801423866526633816082921442883095463259080471819329201710147828025221385656340207489796317663278872207607791034431700112753558813478888727503825389066823098683355695718137867882982111710796422706778536913192342733364556727928018953989153106047379741280794091639429908796650294603536651238230626
```

# これまでに試した似たやつ

* [怠惰な FizzBuzz を作ってみた](https://qiita.com/QUANON/items/c77c22b910651b54fe24)
* [ブヒィ 🐷](https://qiita.com/QUANON/items/2f5c4b19e5d8ee9b7a92)