Ruby メタプログラミングで

Ruby メタプログラミングで末尾再帰をループに展開

module LOOP_EX
  class ObjectHolder
    # wrapper object
    attr_reader :value

    def initialize v
      @value = v
    end
  end

  def loop_ex func
    private_name = (" " + func.to_s).to_sym

    # original method is callable by private_name
    alias_method private_name, func

    # redefine original name by wrapping method
    define_method func, lambda {|*args|
      ObjectHolder.new args
    }
    # this method should not use from external
    private func

    # interface for external
    define_method func.to_s + "_loop", lambda {|*args|
      r = ObjectHolder.new args
      while r.kind_of? ObjectHolder do
        r = __send__ private_name, *r.value
      end
      r
    }
  end
end

class Foo
  extend LOOP_EX

  def sum n, acc
    if n > 0 then
      sum (n - 1), (acc + n)
    else
      acc
    end
  end

  loop_ex :sum
end

foo = Foo.new
p foo.sum_loop(100000, 0)

JavaScript の継続渡しを真似するのはエレガントにできなかったので断念。 id:athos:20110119:p1 のコードをリファクタリングした感じ。マルチスレッドセーフになっています