関数型っぽくフィボナッチ

ブログの間が空きすぎたときの、オイラープロジェクト。25問目フィボナッチ数列で初めて1000桁を超えるのはいくつ目か、という問題。

普通にクラスを作ってメモ化。

class Fib
  def initialize
    @memo = {}
  end

  def calc(n)
    @memo[n] ||= begin
      (n <= 2) ? 1: calc(n - 1) + calc(n - 2)
    end
  end
end

f = Fib.new

(1..10000).each do |n|
  if f.calc(n).to_s.size >= 1000 then
    print n, ":", f.calc(n), "\n"
    break
  end
end

というか、ふつうに下から計算すればカンタンだし速い。

i = 3
x, y = 1, 2

while y.to_s.size < 1000
  x, y = y, x + y
  i += 1
end

puts i

関数型っぽく、関数を受け取ってメモ化を有効にするアプローチ。

def memoize
  h = {}
  lambda {|n| h.has_key?(n) ? h[n]: (h[n] = yield n) }
end

fib = memoize { |n|
  (n <= 2) ? 1: fib.(n - 1) + fib.(n - 2)
}

1.upto(12) do |i| 
  puts fib.(i)
end

(12..10000).each do |n|
  f = fib.(n)
  if f.to_s.size >= 1000 then
    print n, ":", f, "\n"
    break
  end
end

Rubyっぽくない。