Функция выхода Ruby в отношении информатики

Недавно я обнаружил блоки Ruby и уступающие функции, и мне было интересно: где это соответствует теории компьютерных наук? Это функциональный метод программирования или что-то более конкретное?

Ответ 1

Ruby yield не является итератором, как в С# и Python. yield сам по себе действительно очень простая концепция, как только вы понимаете, как блоки работают в Ruby.

Да, блоки являются функциональной функцией программирования, хотя Ruby не является надлежащим образом функциональным языком. На самом деле Ruby использует метод lambda для создания блочных объектов, который заимствован из синтаксиса Lisp для создания анонимных функций - вот какие блоки. С точки зрения компьютерных наук блоки Ruby (и Lisp лямбда-функции) заключаются в закрытиях. В Ruby методы обычно принимают только один блок. (Вы можете передать больше, но это неудобно.)

Ключевое слово yield в Ruby - это просто способ вызова блока, который был передан методу. Эти два примера эквивалентны:

def with_log
  output = yield # We're calling our block here with yield
  puts "Returned value is #{output}"
end

def with_log(&stuff_to_do) # the & tells Ruby to convert into
                           # an object without calling lambda
  output = stuff_to_do.call # We're explicitly calling the block here
  puts "Returned value is #{output}"
end

В первом случае мы просто предполагаем наличие блока и говорим, чтобы его называть. В другом случае Ruby обертывает блок в объект и передает его в качестве аргумента. Первый - более эффективный и читаемый, но они практически одинаковы. Вы бы назвали одно из следующих:

with_log do
  a = 5
  other_num = gets.to_i
  @my_var = a + other_num
end

И он напечатает значение, которое получило бы присвоение @my_var. (ОК, так что это абсолютно глупая функция, но я думаю, что вы поняли эту идею.)

Блоки используются для многих вещей в Ruby. Почти в каждом месте, где вы бы использовали цикл на языке Java, он заменил в Ruby на методы, которые принимают блоки. Например,

[1,2,3].each {|value| print value} # prints "123"
[1,2,3].map {|value| 2**value}    # returns [2, 4, 8]
[1,2,3].reject {|value| value % 2 == 0} # returns [1, 3]

Как отметил Андрей, он также обычно используется для открытия файлов и многих других мест. В принципе, в любое время, когда у вас есть стандартная функция, которая может использовать некоторую пользовательскую логику (например, сортировку массива или обработку файла), вы будете использовать блок. Есть и другие виды использования, но этот ответ уже так долго, я боюсь, это вызовет сердечные приступы у читателей с более слабыми конституциями. Надеюсь, это устранит путаницу в этой теме.

Ответ 2

Там больше, чтобы получить и блокировать, чем просто цикл.

Серия Перечисление перечислимого содержит ряд вещей, которые вы можете делать с перечислениями, например, спрашиваете, истинно ли утверждение для любого члена или, если это верно для всех членов, или для поиска всех или всех членов, удовлетворяющих определенному условию.

Блоки также полезны для переменной области. Вместо того, чтобы просто быть удобным, это может помочь с хорошим дизайном. Например, код

File.open("filename", "w") do |f|
  f.puts "text"
end

гарантирует, что поток файлов будет закрыт, когда вы закончите с ним, даже если возникнет исключение, и что переменная выходит за пределы области действия после ее завершения.

Случайный google не придумал хорошее сообщение в блоге о блоках и доходности в рубине. Я не знаю, почему.

Ответ на комментарий:

Я подозреваю, что он закрывается из-за окончания блока, а не потому, что переменная выходит за пределы области.

Я понимаю, что ничего особенного не происходит, когда последняя переменная, указывающая на объект, выходит за пределы области, кроме того, что этот объект имеет право на сбор мусора. Однако я не знаю, как это подтвердить.

Я могу показать, что объект файла закрывается, прежде чем он получает собранный мусор, что обычно происходит не сразу. В следующем примере вы можете увидеть, что файл-объект закрыт во втором выражении puts, но он не был собран мусором.

g = nil
File.open("/dev/null") do |f|
  puts f.inspect # #<File:/dev/null>
  puts f.object_id # Some number like 70233884832420
  g = f
end
puts g.inspect # #<File:/dev/null (closed)>
puts g.object_id # The exact same number as the one printed out above,
  # indicating that g points to the exact same object that f pointed to

Ответ 3

Я думаю, что оператор yield возник из CLU. Я всегда задаюсь вопросом, был ли персонаж из Трона назван в честь CLU тоже....

Ответ 4

Я думаю, 'coroutine' - это ключевое слово, которое вы ищете.

например. http://en.wikipedia.org/wiki/Yield

Доходность в области вычислительной техники и информатики:

  • в информатике, точка возврата (и повторного ввода) сопрограммы