2010-12-02 3 views
0

Я знаю о Object#tap, который принимает значение и возвращает это значение. Но есть ли метод, который принимает блок и возвращает значение, оцениваемое блоком?Есть ли метод ruby, который просто возвращает значение блока?

Чтобы улучшить свой код в this answer (который является более сложным, чем ниже фрагменте кода), я хотел бы изменить

deck.index("A").tap {|index| 
    STDERR.puts "Result of indexing for #{"A".inspect} is #{index.inspect}" 
} 

, который повторил "A", в

def my_method(*args) 
    yield *args 
end 

deck = ['A', 'B', 'C'] 
my_method("A") {|value| deck.index(value).tap {|index| 
    STDERR.puts "Result of indexing for #{value.inspect} is #{index.inspect}" 
} } 
# Result of indexing for "A" is 0 
# => 0 

ответ

2

Что вы поиск по существу эквивалентен let в Lisp или OCaml - что-то, что позволяет временно привязать значение к идентификатору, не вводя новую переменную в большую область. В Ruby нет ничего, что позволяло бы делать такую ​​вещь с этим синтаксисом. Эквивалент рубин будет:

lambda {|value| deck.index(value).tap {|index| 
    STDERR.puts "Result of indexing for #{value.inspect} is #{index.inspect}" 
} }.call 'A' 

Вы могли бы, конечно, просто написать метод, как:

def let(*values) 
    yield *values 
end 
+0

Можно ли ставить ` 'A'` ближе к началу, а не ближе к концу? – 2010-12-03 00:18:58

0

Я думаю, вы могли бы решить эту проблему с волокнами. Что-то вроде:

def myfiber 
    block = lambda{nil} 
    loop{ block = Fiber.yield(block.call) } 
end 
f = Fiber.new {myfiber } 
f.resume 

puts "result: #{f.resume(lambda{1})}" 
puts "result: #{f.resume(lambda{5})}" 
puts "result: #{f.resume(lambda{2})}" 

приведет:

result: 1 
result: 5 
result: 2