Ruby Pascal';带记忆的s三角发生器

Ruby Pascal';带记忆的s三角发生器,ruby,closures,memoization,Ruby,Closures,Memoization,作为一个Ruby学习实验,我正在尝试记忆我的Pascal三角形生成器的实现。我有以下工作代码: module PascalMemo @cache = {} def PascalMemo::get(r,c) if @cache[[r,c]].nil? then if c == 0 || c == r then @cache[[r,c]] = 1 else @cache[[r,c]] = PascalMemo::get(r

作为一个Ruby学习实验,我正在尝试记忆我的Pascal三角形生成器的实现。我有以下工作代码:

module PascalMemo
  @cache = {}
  def PascalMemo::get(r,c)
    if @cache[[r,c]].nil? then 
      if c == 0 || c == r then 
        @cache[[r,c]] = 1
      else
        @cache[[r,c]] = PascalMemo::get(r - 1, c) + PascalMemo::get(r - 1, c - 1)
      end
    end
    @cache[[r,c]]
  end
end

def pascal_memo (r,c)
  PascalMemo::get(r,c)
end
这能更简洁吗?具体地说,我可以创建一个全局作用域函数和一个局部闭包吗

这能更简洁吗

这似乎很清楚,IMO,
module
ing通常是一种良好的本能

我能用一个局部闭包创建一个全局作用域函数吗

另一个选项是递归的
lambda

memo = {}

pascal_memo = lambda do |r, c|
  if memo[[r,c]].nil?
    if c == 0 || c == r
      memo[[r,c]] = 1
    else
      memo[[r,c]] = pascal_memo[r - 1, c] + pascal_memo[r - 1, c - 1]
    end
  end
  memo[[r,c]]
end

pascal_memo[10, 2]
# => 45

请注意,上述构造确实实现了记忆化,它不仅仅是一个简单的递归方法。

我找到了一种方法来实现我想要的稍微更令人满意,因为它生成的是一个函数而不是lambda:

class << self
  cache = {}

  define_method :pascal_memo do |r,c|
    cache[[r,c]] or 
    (if c == 0 or c == r then cache[[r,c]] = 1 else nil end) or 
    cache[[r,c]] = pascal_memo(r-1,c) + pascal_memo(r-1,c-1)
  end
end

类如果我可以问的话,
@cache
实例变量属于哪个对象?@BorisStitnicky:很好,这是一个复制粘贴延迟。根本不需要实例变量这很有用,因为我不知道如何创建递归lambda。然而,我接受了另一个答案,因为它没有将缓存留在全局范围内。我从中学到了很多。我不想留下
pascal\u memo
工厂函数,但我能够通过将工厂函数本身设置为lambda,并将
p
分配给内联调用它的结果来实现这一点。
(r,c)
语法糖对我来说也是新的。最后,函数本身在如何构建缓存方面很聪明——尽管在这方面它牺牲了相当多的可读性:(我很高兴它有帮助。至于缓存构建,我只是尝试提出一个替代方案。请注意,缓存本身是在存储在lambda绑定中的局部变量中构建的,而不是在main中。
class << self
  cache = {}

  define_method :pascal_memo do |r,c|
    cache[[r,c]] or 
    (if c == 0 or c == r then cache[[r,c]] = 1 else nil end) or 
    cache[[r,c]] = pascal_memo(r-1,c) + pascal_memo(r-1,c-1)
  end
end