Ruby中的递归lambda函数

4
我有以下代码,可以正确生成所有大小为num的树:
class Tree
  attr_accessor :left, :right

  def initialize left = nil, right = nil
    @left = left
    @right = right
  end

  # Don't ever specify any arguments, it will make me very angry.
  # Tilt your head 90 degrees to the side to see the tree when viewing.
  def print level = 0
    @right.pretty_print(level + 1) if @right
    puts ('  ' * level) + to_s
    @left.pretty_print(level + 1) if @left
  end

  def self.generate num
    trees = []
    generate_subtrees(num) { |tree| trees << tree } if num > 0
    trees
  end

  private

  def self.generate_subtrees num, &block
    if num == 0
      yield nil
    else
      (1..num).each do |root_position|
        generate_subtrees(root_position - 1) do |left|
          generate_subtrees(num - root_position) do |right|
            yield Tree.new nil, left, right
          end
        end
      end
    end
  end
end

我正在尝试(出于好奇)使用lambda递归将此内容“压缩”为一个方法。以下是我的当前尝试(经过多次迭代):
def self.generate num
  trees = []

  gen = ->(num, &block) do
    if num == 0
      yield nil                                       # L61
    else
      (1..num).each do |root_position|                # L63
        gen.call(root_position - 1) do |left|         # L64
          gen.call(num - root_position) do |right|
            block.call { Tree.new nil, left, right }
          end
        end
      end
    end
  end

  gen.call(num) { |tree| trees << tree }              # L73

  trees
end

这导致了错误(参考上面提到的行):
LocalJumpError: no block given (yield)
    from tree.rb:61:in `block in generate'
    from tree.rb:64:in `call'
    from tree.rb:64:in `block (2 levels) in generate'
    from tree.rb:63:in `each'
    from tree.rb:63:in `block in generate'
    from tree.rb:73:in `call'
    from tree.rb:73:in `generate'
    from (irb):4
    from /Users/amarshall/.rbenv/versions/1.9.2-p290/bin/irb:12:in `<main>'

我做错了什么?欢迎提供其他解决这个主要是学术问题的方案。


感谢您的编辑,Dave!我从来就没能正确拼写lambda表达式... - Andrew Marshall
你应该发布一些Tree类的最小代码,这样我们就可以轻松地测试此函数的新版本。 - David Grayson
@DavidGrayson 我已经按照你的要求发布了更多的Tree类内容(虽然不是全部,如果我的最小化有任何错误,请告诉我)。 - Andrew Marshall
1个回答

3

yield关键字无法在lambda内部使用。替代方法是使用&block,就像您已经在第64和65行中所做的那样:

gen = ->(num, &block) do
if num == 0
  block.call(nil)
else
  # ...
end

gen.call(num) { |tree| trees << tree } 

我发誓我已经改过那个了(至少在某个时候我可能改过,但是其他一些东西的组合出了问题)。此外,这指出了在线66处我应该使用括号而不是花括号。谢谢! - Andrew Marshall

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接