我想出了这个:
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
还有其他办法吗?
答案 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