11.2.5. Использование продолжений для реализации генератора
11.2.5. Использование продолжений для реализации генератора
Одно из самых трудных для понимания средств Ruby — продолжение (continuation). Это структурированный способ выполнить нелокальный переход и возврат. В объекте продолжения хранятся адрес возврата и контекст выполнения. В каком-то смысле это аналог функций setjmp/longjmp в языке С, но объем сохраняемого контекста больше.
Метод callcc из модуля Kernel принимает блок и возвращает объект класса Continuation. Возвращаемый объект передается в блок как параметр, что еще больше все запутывает.
В классе Continuation есть всего один метод call, который обеспечивает нелокальный возврат в конец блока callсс. Выйти из метода callcc можно либо достигнув конца блока, либо вызвав метод call.
Считайте, что продолжение — что-то вроде операции «сохранить игру» в классических «бродилках». Вы сохраняете игру в точке, где все спокойно, а потом пробуете выполнить нечто потенциально опасное. Если эксперимент заканчивается гибелью, то вы восстанавливаете сохраненное состояние игры и пробуете пойти другим путем.
Самый лучший способ разобраться в продолжениях — посмотреть фильм «Беги, Лола, беги».
Есть несколько хороших примеров того, как пользоваться продолжениями. Самые лучшие предложил Джим Вайрих (Jim Weirich). Ниже показано, как Джим реализовал «генератор» после дискуссии еще с одним программистом на Ruby, Хью Сассе (Hugh Sasse).
Идея генератора навеяна методом suspend из языка Icon (он есть также в Prolog), который позволяет возобновить выполнение функции с места, следующего за тем, где она в последний раз вернула значение. Хью называет это «yield наоборот».
Библиотека generator теперь входит в дистрибутив Ruby. Дополнительную информацию по этому вопросу вы найдете в разделе 8.3.7.
В листинге 11.15 представлена предложенная Джимом реализация генератора чисел Фибоначчи. Продолжения применяются для того, чтобы сохранить состояние между вызовами.
Листинг 11.15. Генератор чисел Фибоначчи
class Generator
def initialize
do_generation
end
def next
callcc do |here|
@main_context = here;
@generator_context.call
end
end
private
def do_generation
callcc do |context|
@generator_context = context;
return
end
generating_loop
end
def generate(value)
callcc do |context|
@generator_context = context;
@main_context.call(value)
end
end
end
# Порождаем подкласс и определяем метод generating_loop.
class FibGenerator < Generator
def generating_loop
generate(1)
a, b = 1, 1
loop do
generate(b)
a, b = b, a+b
end
end
end
# Создаем объект этого класса...
fib = FibGenerator.new
puts fib.next # 1
puts fib.next # 1
puts fib.next # 2
puts fib.next # 3
puts fib.next # 5
puts fib.next # 8
puts fib.next # 13
# И так далее...
Есть, конечно, и более практичные применения продолжений. Один из примеров — каркас Borges для разработки Web-приложений (названный в честь Хорхе Луиса Борхеса), который построен по образу Seaside. В этой парадигме традиционный поток управления в Web-приложении «вывернут с изнанки на лицо», так что логика представляется «нормальной». Например, вы отображаете страницу, получаете результат из формы, отображаете следующую страницу и так далее, ни в чем не противореча интуитивным ожиданиям.
Проблема в том, что продолжение — «дорогая» операция. Необходимо сохранить состояние и потратить заметное время на переключение контекста. Если производительность для вас критична, прибегайте к продолжениям с осторожностью.
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКДанный текст является ознакомительным фрагментом.
Читайте также
Реализации процессора AS/400
Реализации процессора AS/400 Первые использовавшиеся в AS/400 RISC-процессоры поддерживали только режим активных тегов и только структуру ввода-вывода AS/400. Поэтому они выполняли приложения, но не операционные системы, написанные для стандартного процессора PowerPC. Любая другая
Стратегии реализации TCP
Стратегии реализации TCP Рассмотренный стандарт протокола TCP определяет взаимодействие между удаленными объектами, достаточное для обеспечения совместимых реализаций. Другими словами, модуль протокола, в точности следующий спецификации стандарта, является
15.1.4 Реализации NFS и RPC
15.1.4 Реализации NFS и RPC NFS и RPC были реализованы многими разработчиками систем Unix, а также перенесены во многие лицензированные операционные системы. Например, IBM VM, IBM MVS и DEC VAX VMS могут работать как файловые серверы NFS.Некоторые разработчики объединили программное
Другой пример исследования генератора на базе моста Вина
Другой пример исследования генератора на базе моста Вина Предположим теперь, что мы задали параметры элементов в схеме генератора на базе моста Вина, но не знаем частоту колебаний. Нам необходимо определить, возникнут ли колебания, и какова будет их частота. Мы
Реализации. NET
Реализации. NET В настоящий момент существует несколько реализаций того, что мы называем. NET.1. NET Framework – версия среды выполнения для серверных и настольных компьютеров с операционной системой Microsoft Windows. Она поставляется в составе операционных систем Windows XP Tablet Edition и Windows
От идеи к реализации
От идеи к реализации Перейдите от мозговых штурмов — к эскизам — к HTML — к кодированиюВот процесс Get Real, который мы используем:Мозговой штурмНачинайте с идеи. Что этот продукт собирается делать? Для Basecamp, мы смотрели на свои собственные потребности. Мы хотели сделать
Замечания по Реализации
Замечания по Реализации Во время написания этой книги все реализации С++ использовали версии единственного интерфейсного компилятора*. Он используется на многих архитектурах, включая действующие версии системы операционной системы UNIX на AT amp;T 3B, DEC VAX, IBM 370 и Motorolla 68000.
5.3 Интерфейсы и Реализации
5.3 Интерфейсы и Реализации Что представляет собой хороший класс? Нечто, имеющее нбольшое и хорошо определенное множество действий. Нечто, что можно рассматривать как «черный ящик», которым манипулируют только посредством этого множества действий. Нечто, чье фатическое
5.3.1 Альтернативные Реализации
5.3.1 Альтернативные Реализации Пока описание открытой части класса и описание функций членов остаются неизменными, реализацию класса можно модифцировать не влияя на ее пользователей. Как пример этого расмотрим таблицу имен, которая использовалась в настольном
Различные реализации
Различные реализации Чтобы лучше понять всю важность описаний абстрактных типов данных, исследуем глубже потенциальные последствия использования физической реализации в качестве основы описания объектов.Удобным и хорошо изученным примером является описание
Инварианты реализации
Инварианты реализации Некоторые утверждения появляются в реализации, хотя они не имеют прямых двойников в спецификации АТД. Эти утверждения используют атрибуты, включая некоторые закрытые атрибуты, которые, по определению, не имеют смысла в АТД. Простым примером
У11.5 Инвариант реализации
У11.5 Инвариант реализации Напишите инвариант реализации для класса
О реализации динамического связывания
О реализации динамического связывания Может возникнуть опасение, что динамическое связывание - это дорогой механизм, требующий во время выполнения поиска по графу наследования и поэтому накладных расходов, растущих с увеличением глубины этого графа.К счастью, это не
Проблемы реализации
Проблемы реализации Хотя варианты реализации PKI могут отличаться компонентами и деталями, существуют некоторые главные критерии принятия решений:* назначение PKI;* время, необходимое для подготовки к функционированию PKI;* возможность контроля среды пользователей;*
Фултон Хэл
Просмотр ограничен
Смотрите доступные для ознакомления главы 👉