Я придумал это:
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
Есть ли другой способ?
Я придумал это:
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
Есть ли другой способ?
Это зависит от особенностей вашего реального кода, но, учитывая ваш пример, если вы назовете блок заранее, вы можете избежать ввода значения и блока в своей функции. Например:
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 combinator. Как только у меня будет что-то лучше для вас, я обновлю это сообщение.
Блок может рекурсивно вызывать себя, если он хранится в переменной, доступной самому блоку. Например:
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
def f(x, &b)
b.call x
f(x-1,&b) if x>0
end
f(4) do |x|
p x
end
Мэтт ответ хороший. Это также единственный способ реализовать немедленное возвращение из глубокого рекурсивного поиска. Обратите внимание, что возврат из блока фактически возвращается из вызывающей функции. разматывая все рекурсивные вызовы блоков одним махом.
существует множество способов сделать это с помощью 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