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

时间:2009-11-23 23:39:38

标签: ruby

我想出了这个:

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 个答案:

答案 0 :(得分:4)

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

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组合器的一个很好的应用。只要我有更好的东西,我就会更新此消息。

答案 1 :(得分:2)

如果块存储在块本身可访问的变量中,则块可以递归调用自身。例如:

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

答案 2 :(得分:1)

def f(x, &b)
  b.call x
  f(x-1,&b) if x>0
end

f(4) do |x|
 p x
end

答案 3 :(得分:0)

马特的回答很好。它也是实现深度递归搜索立即返回的唯一方法。请注意,从块返回实际上从调用函数返回。一举解开所有递归阻塞调用。

答案 4 :(得分:0)

使用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