代码之家  ›  专栏  ›  技术社区  ›  DigitalRoss

从关联块中递归调用Ruby方法。还有别的办法吗?

  •  10
  • DigitalRoss  · 技术社区  · 15 年前

    我想到了这个:

    def f x, &b
      yield x, b
    end
    f 4 do |i, b|
      p i
      f i - 1, &b if i > 0
    end
    

    4
    3
    2
    1
    0
    

    还有别的办法吗?

    5 回复  |  直到 15 年前
        1
  •  4
  •   Ian Eccles    15 年前

    它取决于实际代码的细节,但是给定示例,如果事先命名块,则可以避免在函数中生成值和块。如:

    def f(x, &b)
      yield x
    end
    
    foo = lambda do |i|
      p i
      f(i-1,&foo) if i > 0
    end
    f(4,&foo)
    

    不过,我想找到一个更优雅的解决方案来解决这个问题。我想这是一个很好的应用Y组合。一旦我有更好的消息给你,我会更新这个消息。

        2
  •  2
  •   Matt Connolly    11 年前

    一个块可以递归地调用自己,只要它存储在一个可由块本身访问的变量中。例如:

    def f(x)
      block = lambda do |y|
        # some calculation on value, or simply yield to the block passed to f()
        yield y
        block.call(y - 1) if y > 0
      end
      block.call(x)
    end
    
    f(4) do |x|
      puts "Yielded block: #{x}"
    end
    

    或者,可以返回递归块,绑定到调用者块,然后调用该块。例如:

    def g
      block = lambda do |y|
        # some calculation on value, or simply yield to block passed to g()
        yield y
        block.call(y - 1) if y > 0
      end
    end
    
    printing_descender = g do |x|
      puts "Encapsulated block: #{x}"
    end
    printing_descender.call(4)
    

    Yielded block: 4
    Yielded block: 3
    Yielded block: 2
    Yielded block: 1
    Yielded block: 0
    Encapsulated block: 4
    Encapsulated block: 3
    Encapsulated block: 2
    Encapsulated block: 1
    Encapsulated block: 0
    
        3
  •  1
  •   DigitalRoss    15 年前
    def f(x, &b)
      b.call x
      f(x-1,&b) if x>0
    end
    
    f(4) do |x|
     p x
    end
    
        4
  •  0
  •   cliffordheath    11 年前

    马特的回答很好。这也是实现深度递归搜索立即返回的唯一方法。注意,从块返回实际上从调用函数返回。一次性解除所有递归块调用。

        5
  •  0
  •   user3377715    11 年前

    使用callcc或catch/throw(总是可以从深度递归调用返回)来实现这一点有很多种方法。这是使用线程本地变量的非高尔夫版本

    def f x, &b
      t = Thread.current
      t[:b] ||= b
      b ||= t[:b]
      b.call(x)
    ensure
      t[:b] = nil
    end
    
    f 4 do |i|
      p i
      f i - 1 if i > 0
    end