Рекурсивные лямбды в рубине - PullRequest
3 голосов
/ 26 октября 2011

У меня есть следующий код, который правильно генерирует все возможные деревья размером 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

Я пытаюсь (ради этого) «сжать» это в один метод, используялямбда-рекурсия.Моя текущая попытка (из нескольких итераций) ниже:

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>'

Что я делаю неправильно?Альтернативные решения этой в основном академической проблемы также приветствуются.

1 Ответ

3 голосов
/ 26 октября 2011

Ключевое слово yield не работает внутри лямбды.Альтернатива - использовать &block, так же, как вы уже используете строки 64 и 65:

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

gen.call(num) { |tree| trees << tree } 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...