我正在尝试编写一个函数来统一memoize Ruby中的任何函数(如本文第6页所述,它在Python中执行相同的操作:http://courses.csail.mit.edu/6.01/spring07/lectures/lecture4.pdf),但我遇到了问题。这是我的代码,它不起作用(函数被正确评估,但没有被记忆)。谁能告诉我哪里出错?
def fib(n)
return n if n<2
fib(n-1) + fib(n-2)
end
def memoize(&f)
memo = {}
doit = ->(arg) do
return memo[arg] if memo[arg]
memo[arg] = f.call(arg)
memo[arg]
end
doit
end
fib = memoize{|x| fib(x)}
puts fib.call(50)
答案 0 :(得分:6)
fib
以递归方式调用自身,通过这样做,完全绕过了memoization逻辑。无论选择哪种方法,都必须覆盖fib
的原始定义,以便对其进行包含记忆。
@Aetherus给出了一个有效的答案。这是一个更动态的解决方案:
def fib(n)
return n if n<2
fib(n-1) + fib(n-2)
end
def memoize(method_name)
memo = {}
old_fib = method(method_name)
define_method(method_name) do |arg|
return memo[arg] if memo[arg]
memo[arg] = old_fib.call(arg)
memo[arg]
end
end
memoize(:fib)
puts fib(50)
答案 1 :(得分:1)
您可以使用方法装饰器模式,here是一个可用作库的示例实现:
require "method_decorators/memoize" class MyMath extend MethodDecorators +MethodDecorators::Memoize def self.fib(n) if n <= 1 1 else fib(n - 1) * fib(n - 2) end end end puts MyMath.fib(200)
答案 2 :(得分:0)
在python中,函数是可调用对象,它们的名称只是存储这些对象的变量的名称,因此您只需为该变量赋值即可使函数函数完全不同。
但是在ruby中,方法不是对象,它们的名称也不是变量名。要覆盖原始内容,您必须再次def
。
这是我的解决方案:
def fib(n)
return n if n<2
fib(n-1) + fib(n-2)
end
alias _fib fib
def fib(n)
$memo ||= {}
$memo[n] ||= _fib(n)
end
fib(50) #=> 12586269025
我使用了旧的红宝石技巧:制作别名并覆盖原始。这是令人讨厌的(因为在重写之后还有一个额外的_fib
),但这是最简单的方法。