Продолжение

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

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

«текущее продолжение » или «продолжение этапа вычислений» - это продолжение, которое, с точки зрения выполняемого кода, могло бы быть получено из текущей точки выполнения программы. Термин «продолжения» также может использоваться для обозначения первоклассных продолжений, которые представляют собой конструкции, которые дают языку программирования возможность сохранять состояние выполнения в любой момент и возвращаться к этой точке. позже в программе, возможно, несколько раз.

Содержание
  • 1 История
  • 2 Первоклассные продолжения
    • 2.1 Использование
    • 2.2 Примеры
      • 2.2.1 Сопрограммы
    • 2.3 Реализация
    • 2.4 Поддержка языков программирования
  • 3 В веб-разработке
  • 4 вида
  • 5 Недостатки
  • 6 Лингвистика
  • 7 См. Также
  • 8 Ссылки
  • 9 Дополнительная литература
  • 10 Внешние ссылки
История

Самое раннее описание продолжений было сделано Адрианом ван Вейнгаарденом в сентябре 1964 года. Вейнгаарден выступал на Рабочей конференции IFIP по языкам описания формальных языков, проходившей в Баден-бай-Вена, Австрия. В рамках разработки препроцессора Algol 60 он призвал преобразовать соответствующие процедуры в стиль передачи продолжения, хотя он не использовал это имя, и его намерение состояло в том, чтобы упростить программу и тем самым сделать ее результат более понятным.

Кристофер Стрейчи и Джон К. Рейнольдс выдвинули термин «продолжение» на видное место в своей работе в области денотационной семантики, которая широко использует продолжения, чтобы позволить последовательное программы, подлежащие анализу с точки зрения семантики функционального программирования.

Стив Рассел изобрел продолжение в своей второй реализации Lisp для IBM 704, хотя он не назвал это.

Рейнольдс (1993) дает полную историю открытия продолжений.

Первоклассные продолжения

Первоклассные продолжения - это способность языка полностью контролировать порядок выполнения инструкций. Их можно использовать для перехода к функции, которая вызвала вызов текущей функции, или к функции, которая ранее завершилась. Можно думать о первоклассном продолжении как о сохранении состояния выполнения программы. Важно отметить, что истинные первоклассные продолжения не сохраняют данные программы - в отличие от образа процесса - только контекст выполнения. Это иллюстрируется описанием «сэндвич продолжения»:

Допустим, вы находитесь на кухне перед холодильником и думаете о сэндвиче. Вы тут же берете продолжение и кладете в карман. Затем вы достаете индейку и хлеб из холодильника и делаете себе бутерброд, который теперь стоит на прилавке. Вы вызываете продолжение в кармане и снова стоите перед холодильником, думая о бутерброде. Но, к счастью, на прилавке есть бутерброд, и все материалы, из которых он сделан, исчезли. Итак, съешь это. :-)

В этом описании сэндвич - это часть данных программы (например, объект в куче), и вместо того, чтобы вызывать процедуру «сделать бутерброд» и затем вернуться, человек назвал «сделать бутерброд с текущее продолжение », которая создает сэндвич и затем продолжает с того места, где было остановлено выполнение.

Схема была первой полноценной производственной системой (1969-1970), обеспечивающей сначала «улов», а затем call / cc. Брюс Дуба представил call / cc в SML.

Продолжения также используются в моделях вычислений, включая денотационную семантику, модель актора, вычисление процессов и лямбда-исчисление. Эти модели полагаются на программистов или инженеров по семантике для написания математических функций в так называемом стиле передачи продолжения. Это означает, что каждая функция использует функцию, которая представляет остальную часть вычислений относительно этого вызова функции. Чтобы вернуть значение, функция вызывает эту «функцию продолжения» с возвращаемым значением; чтобы прервать вычисление, он возвращает значение.

Функциональные программисты, которые пишут свои программы в стиле передачи продолжения, получают выразительную способность манипулировать потоком управления произвольными способами. Цена состоит в том, что они должны поддерживать инварианты управления и продолжения вручную, что может быть очень сложной задачей (но см. «Стиль передачи продолжения» ниже).

Использование

Продолжение упрощает и разъясняет реализацию нескольких общих шаблонов проектирования , включая сопрограммы / зеленые потоки и обработка исключений, предоставляя базовый низкоуровневый примитив, который объединяет эти, казалось бы, несвязанные шаблоны. Продолжения могут предоставить элегантные решения некоторых сложных проблем высокого уровня, таких как программирование веб-сервера, поддерживающего несколько страниц, доступ к которым осуществляется с помощью кнопок вперед и назад и по ссылкам. Веб-среда Smalltalk Seaside очень эффективно использует продолжения, позволяя программировать веб-сервер в процедурном стиле, переключая продолжения при переключении страниц.

Также существуют более сложные конструкции, для которых «продолжения дают элегантное описание». Например, в C, longjmp можно использовать для перехода от середины одной функции к другой, при условии, что вторая функция лежит глубже в стеке (если она ожидает, пока первая функция вернуться, возможно, среди прочего). Другие более сложные примеры включают сопрограммы в Simula 67, Lua и Perl ; тасклеты в Stackless Python ; генераторы в Icon и Python ; продолжения в Scala (начиная с 2.8); волокна в Ruby (начиная с 1.9.1); механизм возврата в Prolog ; монады в функциональном программировании ; и потоки.

Примеры

Язык программирования Scheme включает в себя управляющий оператор call-with-current-continue (сокращенно: call / cc) с помощью которого программа Scheme может манипулировать потоком управления:

(define the-continue #f) (define (test) (let ((i 0)); call / cc вызывает свой первый аргумент функции, передавая; продолжение переменная, представляющая эту точку в; программе в качестве аргумента этой функции.;; В этом случае аргумент функции присваивает это продолжение переменной the-continue.; (call / cc (lambda (k) (set! the- continue k)));; В следующий раз, когда вызывается продолжение, мы начнем здесь. (set! i (+ i 1)) i))

Определяет функцию test, которая устанавливает продолжениек будущему состоянию выполнения самого себя:

>(тест) 1>(продолжение) 2>(продолжение) 3>; сохраняет текущее продолжение (которое напечатает 4 следующих) прочь>(определить продолжение продолжения)>(тест); сбрасывает продолжение 1>(продолжение) 2>(продолжение другого); использует ранее сохраненное продолжение 4

Для более мягкого введения в этот механизм см. call-with-current-continue.

Coroutines

В этом примере показано возможное использование продолжений для реализации сопрограммы как отдельные потоки.

;;; Наивная очередь для планирования потоков. ;;; Он содержит список продолжений, «ожидающих запуска». (define * queue * '()) (define (empty-queue?) (null? * queue *)) (define (enqueue x) (set! * queue * (append * queue * (list x)))) ( define (dequeue) (let ((x (car * queue *))) (set! * queue * (cdr * queue *)) x)) ;;; Это запускает новый поток (процесс). (define (fork proc) (call / cc (lambda (k) (enqueue k) (proc)))) ;;; Это передает процессор другому потоку, если он есть. (define (yield) (call / cc (lambda (k) (enqueue k) ((dequeue))))) ;;; Это завершает текущий поток или всю программу ;;; если не осталось других нитей. (define (thread-exit) (if (empty-queue?) (exit) ((dequeue))))

Определенные выше функции позволяют определять и выполнять потоки с помощью совместной многозадачности, т. е. потоков которые передают управление следующему в очереди:

;;; Тело некоторого типичного потока схемы, который выполняет что-то: (define (do-stuff-n-print str) (lambda () (let loop ((n 0)) (format #t "~ A ~ A \ n" str n) (yield) (loop (+ n 1))))) ;;; Создайте два потока и запустите их. (fork (do-stuff-n-print "Это AAA")) (fork (do-stuff-n-print "Hello from BBB")) (thread-exit)

Предыдущий код даст следующий результат:

Это AAA 0 Привет от BBB 0 Это AAA 1 Привет от BBB 1 Это AAA 2 Привет от BBB 2...

Реализация

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

Поддержка языков программирования

Многие языки программирования демонстрируют первоклассные продолжения под разными именами; в частности:

. На любом языке, который поддерживает закрытие и соответствующие хвостовые вызовы, можно писать программы на стиль передачи продолжения и ma обычно реализуйте call / cc. (В стиле передачи продолжения call / cc становится простой функцией, которую можно записать с помощью лямбда.) Это особенно распространенная стратегия в Haskell, где легко построить «продолжение-передача монады » (например, монада Contи преобразователь монады ContTв библиотеке mtl). Поддержка правильных хвостовых вызовов необходима, потому что в стиле передачи продолжения никакая функция никогда не возвращает; все звонки - хвостовые.

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

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

Некоторые из наиболее популярных веб-серверов с поддержкой продолжения - это Racket веб-сервер, UnCommon Web Framework и Weblocks Web framework для Common Lisp, Seaside framework для Smalltalk, Ocsigen / Eliom для OCaml, Continuity для Perl, Wee для Ruby, Tales Framework для Fantom и Nagare framework для Python, Wt для C ++, MFlow для Haskell. Apache Cocoon Инфраструктура веб-приложений также обеспечивает продолжения (см. руководство по Cocoon ).

Виды

Поддержка продолжений сильно различается. Язык программирования поддерживает повторно вызываемые продолжения, если продолжение можно вызывать повторно (даже после того, как оно уже было возвращено). Повторно вызываемые продолжения были введены Питером Дж. Ландином с помощью оператора J (для перехода), который мог передавать поток управления обратно в середину вызова процедуры. Повторно вызываемые продолжения также называются «реентерабельными» на языке Racket. Однако такое использование термина «повторно входящий» можно легко спутать с его использованием при обсуждении многопоточности.

Более ограниченным видом является escape-продолжение, которое может использоваться для выхода из текущего контекста в окружающий. Многие языки, которые явно не поддерживают продолжения, поддерживают обработку исключений, которая эквивалентна escape-продолжениям и может использоваться для тех же целей. C setjmp/longjmp также эквивалентны: они могут использоваться только для раскрутки стека. Экранирующие продолжения также могут использоваться для реализации исключения хвостовых вызовов.

Одним из обобщений продолжений являются ограниченные продолжения. Операторы продолжения, такие как call / cc, фиксируют все оставшиеся вычисления в заданной точке программы и не предоставляют возможности ограничить этот захват. Операторы продолжения с разделителями решают эту проблему, предоставляя два отдельных механизма управления: подсказку, ограничивающую операцию продолжения, и оператор повторения, такой как shiftили control. Таким образом, продолжения, захваченные с использованием операторов с разделителями, представляют только часть контекста программы.

Недостатки

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

Лингвистика

В разделе «Продолжение и природа количественной оценки» Крис Баркер представил «гипотезу продолжения», что

некоторые лингвистические выражения (в частности, QNPs [количественные выражения существительных]) имеют обозначения, которые манипулируют их собственными продолжениями.

Баркер утверждал, что эту гипотезу можно использовать для объяснения таких явлений, как двойственность значения NP (например, тот факт, что QNP «все» ведет себя совершенно иначе, чем неколичественная фраза существительного «Боб», вносящая вклад в смысл предложения типа «Алиса видит [Боба / всех]»), смещение области действия (например, что «капля дождя упала на каждую машину» обычно интерпретируется как ∀ c ∃ r, упал (r, c) {\ displaystyle \ forall c \ существует r, {\ t_dv {fall}} (r, c)}\ forall c \ exists r, {\ t_dv {упал} } (r, c) , а не как ∃ r ∀ c, упал (r, c) {\ displaystyle \ exists r \ forall c, {\ t_dv {fall}} (r, c)}\ существует r \ forall c, {\ t_dv {fall}} (r, c) ) и неоднозначность области действия (предложение типа "кто-то видел всех" может быть неоднозначным между ∃ x ∀ y, saw (x, y) {\ displaystyle \ существует x \ forall y, {\ t_dv {saw}} (x, y)}\ exists x \ forall y, {\ t_dv {saw}} (x, y) и ∀ y ∃ x, saw (x, y) {\ displaystyle \ forall y \ существует x, {\ t_dv {saw}} (x, y)}\ forall y \ exis ts x, {\ t_dv {saw}} (x, y) ). Он также заметил, что эта идея в некотором роде является естественным продолжением подхода Ричарда Монтегю в «Правильном подходе к количественной оценке в обычном английском» (PTQ), написав, что «с точки зрения ретроспективы, ограниченный форма продолжения передачи четко прослеживается в основе трактовки PTQ Монтегю (1973) NP как обобщенных кванторов ".

Степень, в которой продолжения могут использоваться для объяснения других общих явлений на естественном языке, является темой текущих исследований.

См. Также
Ссылки
Дополнительная литература
  • Питер Лэндин. Обобщение отчетов о скачках и метках. Исследования системного программирования UNIVAC. Август 1965. Перепечатано в «Высшем порядке и символических вычислениях», 11 (2): 125-143, 1998, с предисловием Хайо Тилеке.
  • Дрю МакДермотт и Джерри Сассман. Справочное руководство Conniver MIT AI Memo 259. Май 1972 г.
  • Дэниел Боброу : Модель структур управления для языков программирования с искусственным интеллектом IJCAI 1973 г.
  • Карл Хьюитт, Питер Бишоп и. Универсальный модульный формализм актеров для искусственного интеллекта IJCAI 1973 г.
  • Кристофер Стрейчи и. Продолжение: Математическая семантика для обработки полных прыжков Техническая монография PRG-11. Вычислительная лаборатория Оксфордского университета. Январь 1974 г. Перепечатано в «Higher Order and Symbolic Computing», 13 (1/2): 135–152, 2000, с предисловием Кристофера П. Уодсворта.
  • Джон К. Рейнольдс. Дефинициональные интерпретаторы языков программирования высшего порядка Труды 25-й Национальной конференции ACM, стр. 717–740, 1972 г. Перепечатано в Higher-Order and Symbolic Computation 11 (4): 363-397, 1998, с предисловием.
  • Джон К. Рейнольдс. О связи между прямой и продолжающейся семантическими материалами Второго коллоквиума по автоматам, языкам и программированию. LNCS Vol. 14, pp. 141–156, 1974.
  • Рейнольдс, Джон К. (1993). «Открытия продолжений» (PDF). Лисп и символьные вычисления. 6(3/4): 233–248. CS1 maint: ref = harv (ссылка )
  • Джеральд Сассман и Гай Стил. СХЕМА: Интерпретатор для расширенного лямбда-исчисления AI Memo 349, Лаборатория искусственного интеллекта Массачусетского технологического института, Кембридж, Массачусетс, декабрь 1975 г. Перепечатано в High-Order and Symbolic Computing 11 (4): 405-439, 1998, с предисловием. 288>Р. Кент Дибвиг,. Представление управления в присутствии первоклассных продолжений Труды конференции ACM SIGPLAN '90 по проектированию и реализации языков программирования, стр. 66–77.
  • Уилл Клингер Стратегии реализации для продолжений Труды конференции ACM 1988 г. по LISP и функциональному программированию, стр. 124–131, 1988 г. Журнальная версия: высшие порядки и символьные вычисления, 12 (1): 7-45, 1999.
  • . Обратное обращение инверсии управления или, Продолжение по сравнению с программированием, ориентированным на страницы SIGPLAN Notices 38 (2), pp. 57–64, 2003.
Внешние ссылки
Последняя правка сделана 2021-05-15 10:57:28
Содержание доступно по лицензии CC BY-SA 3.0 (если не указано иное).
Обратная связь: support@alphapedia.ru
Соглашение
О проекте