lambda的方法? Mats的示例代码让我很困惑。

时间:2012-08-13 08:12:15

标签: ruby methods lambda

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

代码来自“红宝石编程语言”。 但它让我感到困惑:方法(memoize)如何应用于lambda作为其方法? lambda后跟其他lambda用点(。)作为自己的方法吗?

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

BTW:上面的代码在irb中有效,但是ruby解释器遇到如下错误:

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

为什么?

2 个答案:

答案 0 :(得分:7)

你在说什么:

def memoize
  #...
end

我想你的意思是这样说:

class Proc
  def memoize
    #...
  end
end

这会为Procs添加一个公共memoize方法,而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. 返回缓存的值。
  4. 您可以使用[]方法执行Proc,因此proc.call(a, b)proc[a, b]相同。

答案 1 :(得分:4)

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

为什么它在irb会话中有效?因为context mode(也是here),默认情况下为 3 。例如,使用值 0 irb --context-mode 0),现在它们将像往常一样作为私有方法添加。

如果片段明确定义了哪个类被修改而不是使用隐式顶级,那么最好是教学目的。