Введение

Представление состояния управления компьютерной программой

В информатике, продолжение — это абстрактное представление состояния управления компьютерной программой. Продолжение реализует (реифицирует) состояние управления программой, то есть является структурой данных, представляющей вычислительный процесс в определенный момент его выполнения; эта структура данных становится доступной языку программирования, а не остаётся скрытой в среде выполнения. Продолжения полезны для реализации других механизмов управления в языках программирования, таких как исключения, генераторы, корутины и так далее. "Текущее продолжение" или "продолжение шага вычисления" — это продолжение, которое, с точки зрения выполняющегося кода, было бы получено из текущей точки выполнения программы. Термин "продолжения" также может относиться к продолжениям первого класса, которые предоставляют языку программирования возможность сохранять состояние выполнения в любой точке и возвращаться к нему позже, возможно, многократно.

История

Самое раннее описание продолжений было сделано Адриааном ван Вейнгаарденом в сентябре 1964 года. Ван Вейнгаарден выступил на рабочей конференции IFIP по языкам описания формальных языков, проходившей в Бадене близ Вены, Австрия. В рамках разработки препроцессора Algol 60 он предложил преобразовать собственные процедуры в стиль передачи продолжений, хотя и не использовал такое название, и его целью было упростить программу и сделать её результат более ясным. Кристофер Стречи, Кристофер П. Уодсворт и Джон К. Рейнольдс сделали термин "продолжение" широко известным в своих работах в области денотационной семантики, которая активно использует продолжения для анализа последовательных программ с точки зрения семантики функционального программирования. Он изобрел продолжение во второй реализации Lisp для IBM 704, хотя и не дал ему названия. [Автор] представляет полную историю открытия продолжений.

Реализация

Программа должна выделять место в памяти для переменных, используемых её функциями. Большинство языков программирования используют стек вызовов для хранения необходимых переменных, поскольку он обеспечивает быстрое и простое выделение памяти и её автоматическое освобождение. Другие языки программирования используют кучу для этого, что обеспечивает большую гибкость, но требует больших затрат на выделение и освобождение памяти. Обе эти реализации имеют свои преимущества и недостатки в контексте продолжений.

В веб-разработке

Одной из областей практического применения продолжений является веб-программирование. Использование продолжений позволяет программисту абстрагироваться от безгосударственной природы протокола HTTP. В традиционной модели веб-программирования отсутствие состояния отражается в структуре программы, что приводит к коду, построенному вокруг модели, которая крайне неудобна для выражения вычислительных задач. Таким образом, продолжения позволяют создавать код, обладающий полезными свойствами, связанными с инверсией управления, избегая при этом присущих ей недостатков. Статья "Инверсия инверсии управления, или Продолжения против программирования, ориентированного на страницы" дает хорошее представление о применении продолжений в веб-программировании.

Виды

Поддержка продолжений сильно различается. Язык программирования поддерживает повторно вызываемые продолжения, если продолжение может быть вызвано многократно (даже после того, как оно уже вернуло значение). Повторно вызываемые продолжения были введены Питером Дж. Ландином с использованием его оператора J (от Jump), который позволял перенести поток управления обратно в середину вызова процедуры. Повторно вызываемые продолжения также называют "реэнтрантными" в языке Racket. Однако такое использование термина "реэнтрантный" может легко быть спутано с его использованием в обсуждениях многопоточности. Более ограниченным типом является продолжение-побег, которое можно использовать для выхода из текущего контекста во внешний. Многие языки, которые явно не поддерживают продолжения, поддерживают обработку исключений, что эквивалентно продолжениям-побегам и может использоваться для тех же целей. Функции setjmp/longjmp в C также эквивалентны: они могут использоваться только для размотки стека. Продолжения-побеги также могут использоваться для реализации устранения хвостовой рекурсии. Обобщением продолжений являются ограниченные продолжения. Операторы продолжений, такие как call/cc, захватывают все оставшееся вычисление в заданной точке программы и не предоставляют способа ограничения этого захвата. Операторы ограниченных продолжений решают эту проблему, предоставляя два отдельных механизма управления: запрос, который ограничивает операцию продолжения, и оператор реификации, такой как shift или control. Продолжения, захваченные с использованием ограниченных операторов, таким образом, представляют собой лишь часть контекста программы.

Недостатки

Продолжения — это функциональное выражение оператора GOTO, и к ним применимы те же ограничения. Хотя в некоторых особых случаях, например, при веб-программировании, они могут быть разумным выбором, использование продолжений может привести к коду, который сложно понять. Фактически, эзотерический язык программирования Unlambda включает вызов по текущему продолжению в качестве одной из своих особенностей исключительно потому, что выражения с его использованием "обычно крайне сложно отследить". Внешние ссылки ниже иллюстрируют эту концепцию более подробно.