I've come up with this:
def f x, &b
yield x, b
end
f 4 do |i, b|
p i
f i - 1, &b if i > 0
end
Result:
4
3
2
1
0
Is there another way?
I've come up with this:
def f x, &b
yield x, b
end
f 4 do |i, b|
p i
f i - 1, &b if i > 0
end
Result:
4
3
2
1
0
Is there another way?
It depends upon the particulars of your actual code, but given your example, if you name the block beforehand, you can avoid yielding the value and the block in your function. Eg:
def f(x, &b)
yield x
end
foo = lambda do |i|
p i
f(i-1,&foo) if i > 0
end
f(4,&foo)
However, I'd like to find a more elegant solution to this problem. I suspect this is would be a good application of the Y combinator. As soon as I have something better for you, I'll update this message.
A block can recursively call itself provided it is stored in a variable that is accessible by the block itself. For example:
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
Alternatively, you can return the recursive block, bound to the callers block and then call that block. For example:
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)
Outputs:
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
def f(x, &b)
b.call x
f(x-1,&b) if x>0
end
f(4) do |x|
p x
end
Matt's answer is good. It's also the only way to implement an immediate return from a deep recursive search. Note that returning from the block actually returns from the invoking function. unwinding all recursive block calls in one fell swoop.
there are tons of ways to do this using callcc, or catch/throw (which can always return from deep recursive calls). here is non-golfing version that uses thread local vars
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