7
def memoize
  cache = {}
  lambda { |*args| 
    unless cache.has_key?(args)
      cache[args] = self[*args]
    end
    cache [args]
  }
end

factorial =  lambda {|x| return 1 if x== 0; x*factorial[x-1];}.memoize

puts factorial.call 10

代码来自《红宝石编程语言》一书。但这让我很困惑:method(memoize) 如何将 lambda 作为它的方法应用?lambda 可以在其他 lambda 之后使用 dot(.) 作为自己的方法吗?

lambda {|x| return 1 if x== 0; x*factorial[x-1];}.memoize

顺便说一句:上面的代码在 irb 中工作,但是 ruby​​ 解释器遇到如下错误:

memoize.rb:11: private method `memoize' called for #<Proc:0x0000000103bba018@memoize.rb:11> (NoMethodError)

为什么?

4

2 回答 2

7

你在哪里说这个:

def memoize
  #...
end

我想你的意思是这样说:

class Proc
  def memoize
    #...
  end
end

这将为memoizeProcs 添加一个公共方法,并且lambda { ... }(或-> { ... }在较新的 Rubies 中)为您提供一个 Proc 实例。

现在谈谈memoize它自己。方法返回它们最后一个表达式的值,对于memoize,最后一个表达式是这样的:

lambda { |*args| 
  unless cache.has_key?(args)
    cache[args] = self[*args]
  end
  cache [args]
}

所以memoize为 Proc ( self) 返回一个包装器,它是一个闭包cache,这个包装器所做的就是:

  1. 检查是否cache有相关参数列表的条目(数组args)。
  2. 如果我们没有缓存值,则计算原始 Proc 的值 ( self[*args]) 并将其存储在缓存中。
  3. 返回缓存的值。

您可以使用该[]方法执行 Proc,因此proc.call(a, b)proc[a, b].

于 2012-08-13T08:28:42.967 回答
4

顶层的对象是main,在那里定义的任何方法都作为私有实例方法添加到Object(因此它们在任何地方都可用)。

为什么它在 irb 会话中起作用?因为上下文模式(也在此处),在 irb 中默认为3。使用例如值0 ( irb --context-mode 0),现在它们将像往常一样作为私有方法添加。

如果代码片段明确定义要修改的类而不是使用隐式顶层,那么出于教学目的可能会更可取。

于 2012-08-13T08:30:01.770 回答