Call-with-current-continue - Call-with-current-continuation

В компьютерное программирование с языком Схема, то подпрограмма или функция вызов с текущим продолжением, сокращенно вызов / cc, используется как поток управления оператор. Он был принят несколькими другими языками программирования.

Принимая функцию ж как единственный аргумент, (звонок / cc f) внутри выражения применяется к текущему продолжение выражения. Например ((call / cc f) e2) эквивалентно применению ж к текущему продолжению выражения. Текущее продолжение дается заменой (звонок / cc f) по переменной c связаны лямбда-абстракцией, поэтому текущее продолжение (лямбда (c) (c e2)). Применение функции ж это дает окончательный результат (f (лямбда (c) (c e2))).

В качестве дополнительного примера в выражении (e1 (вызов / cc f)), продолжение подвыражения (звонок / cc f) является (лямбда (c) (e1 c)), поэтому все выражение эквивалентно (f (лямбда (c) (e1 c)))Другими словами, он берет «снимок» текущего контекста управления или состояния управления программы как объект и применяет ж к нему. Объект продолжения - это первоклассная ценность и представлен как функция, с приложение-функция как его единственная операция. Когда объект продолжения применяется к аргументу, существующее продолжение удаляется, а примененное продолжение восстанавливается на своем месте, так что поток программы будет продолжен в точке, в которой продолжение было захвачено, и аргумент продолжения затем становится "возвращаемым значением" вызова call / cc. Продолжения, созданные с помощью call / cc, могут вызываться более одного раза и даже извне динамического экстента приложения call / cc.

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

С call / cc можно реализовать множество сложных операторов управления из других языков с помощью нескольких строк кода, например, Маккарти с Amb оператор за недетерминированный выбор, Пролог -стиль возврат, Симула 67-стиль сопрограммы и их обобщения, Значок -стиль генераторы, или же двигатели и потоки или даже неясное РОДОМ ИЗ.

Примеры

Как показано в следующем примере, call / cc можно использовать для эмуляции функции заявление о возврате известно из C -стилевые языки, отсутствующие в Схема:

(определять (ж возвращаться)  (возвращаться 2)  3)(дисплей (ж (лямбда (Икс) Икс))) ; отображает 3(дисплей (вызов с текущим продолжением ж)) ; отображает 2

Вызов ж с обычным аргументом функции сначала применяет эту функцию к значению 2, а затем возвращает 3. Однако, когда ж передается в call / cc (как в последней строке примера), применение параметра (продолжения) к 2 заставляет выполнение программы перейти к точке, где был вызван call / cc, и вызывает возврат call / cc значение 2. Затем оно выводится функцией дисплея.

В следующем примере call / cc используется дважды: один раз для генерации продолжения "return", как в первом примере, и один раз для приостановки итерации по списку элементов:

;; [СПИСОК X] -> (-> X u 'ты упал с конца)(определять (генерировать по одному элементу за раз lst)  ;; Обе внутренние функции закрываются над lst  ;; Внутренняя переменная / функция, которая передает текущий элемент в списке  ;; в свой возвращаемый аргумент (который является продолжением) или передает маркер конца списка   ;; если больше не осталось элементов. На каждом шаге имя функции   ;; возврат к продолжению, которое указывает обратно в тело функции,  ;; в то время как return - это возврат к любому продолжению, которое указывает вызывающий.  (определять (контрольное состояние возвращаться)    (для каждого      (лямбда (элемент)               (набор! возвращаться (вызов с текущим продолжением                              (лямбда (резюме здесь)                                ;; Возьмите текущее продолжение                               (набор! контрольное состояние резюме здесь)                               (возвращаться элемент))))) ;; (элемент возврата) означает следующий возврат     lst)    (возвращаться ты упал с конца))    ;; (-> X u 'ты-упал до конца)  ;; Это фактический генератор, производящий по одному элементу из списка за раз.  (определять (генератор)    (вызов с текущим продолжением контрольное состояние))  ;; Вернуть генератор   генератор)(определять генерировать цифру  (генерировать по одному элементу за раз '(0 1 2)))(генерировать цифру) ;; 0(генерировать цифру) ;; 1(генерировать цифру) ;; 2(генерировать цифру) ;; ты упал с конца

Каждый раз, когда цикл собирается обработать другой элемент из списка, функция захватывает текущее продолжение и присваивает его переменной 'control-state'. Эта переменная изначально является закрытие который выполняет итерацию по всем элементам списка. По мере того, как вычисление прогрессирует, оно становится закрытием, которое повторяется через суффикс данного списка. Хотя использование «call / cc» не обязательно для линейной коллекции, такой как [LISTOF X], код обобщается на любой коллекция, которую можно пройти.

Call-with-current-continue также может выражать другие сложные примитивы. Например, в следующем примере выполняется совместная многозадачность с использованием продолжений:

;; Совместная многозадачность с использованием call-with-current-continue;; в 25 строках схемы;; Список потоков, ожидающих запуска. Это список из одного;; функции без возврата аргументов (в основном продолжения);; Продолжение - это невозвратная функция, как и (выход),;; в том, что он никогда не уступает контроль тому, что его называет.(определять готовый список '());; Невозвратная функция. Если есть другой поток;; ожидая запуска, запускается следующий поток, если там;; осталось запустить, в противном случае он вызывает исходный выход;; который выходит из всего окружения.(определять выход  ;; Исходный выход, который мы отменяем.  (позволять ((выход выход))    ;; Основная функция.    (лямбда ()      (если (нет (ноль? готовый список))	  ;; Есть еще один поток, ожидающий запуска.	  ;; Итак, мы его запускаем.          (позволять ((продолжение (машина готовый список)))            (набор! готовый список (CDR готовый список))	    ;; Поскольку готовый список только невозвратный	    ;; функции, это не вернет.            (продолжение #f))	  ;; Больше нечего было бежать.	  ;; Оригинал (выход) - это невозвратная функция,	  ;; так что это невозвратная функция.          (выход)))));; Принимает функцию с одним аргументом с заданным;; аргумент и разветвляет его. Новая функция разветвленной функции;; поток выйдет, если / когда функция когда-либо завершится.(определять (вилка fn аргумент)  (набор! готовый список        (добавить готовый список		;; Эта функция добавлена ​​в 		;; готовый список не возвращается,		;; так как выход не возвращается.		(список		 (лямбда (Икс)		   (fn аргумент)		   (выход))))));; Передает управление следующему потоку, ожидающему запуска.;; Хотя в конечном итоге он вернется, он теряет контроль;; и восстановит его только при вызове продолжения.(определять (Уступать)  (вызов с текущим продолжением   ;; Захватите продолжение, представляющее ЭТОТ вызов, чтобы уступить   (лямбда (продолжение)     ;; Поместите это в готовый список     (набор! готовый список           (добавить готовый список                   (список продолжение)))     ;; Получите следующий поток и запустите его.     (позволять ((продолжение (машина готовый список)))       (набор! готовый список (CDR готовый список))       ;; Запустить его.       (продолжение #f)))))

В 1999 году Дэвид Мадор (изобретатель Unlambda язык программирования) обнаружил 12-символьный термин в Unlambda с поддержкой callcc, который имеет тот же эффект (записать все целые числа в унарной форме) термина из более 600 символов в Unlambda без call / cc.[1] При преобразовании этого термина в схему он получил программу-схему, известную как загадка инь-ян. Тогда при обсуждении call / cc было принято показывать:[2]

(позволять* ((инь         ((лямбда (cc) (дисплей #\@) cc) (вызов с текущим продолжением (лямбда (c) c))))       (Ян         ((лямбда (cc) (дисплей #\*) cc) (вызов с текущим продолжением (лямбда (c) c)))))    (инь Ян))

Иллюстрация загадки: все утверждения в скобках - это состояния инь и ян непосредственно перед (Инь Янь); Число означает, будет ли 1-е продолжение или 2-е для прыжка. Заявление после числа представляет контекст.

;@*[(инь 1 ()) (Ян 2 (инь 1 ()))];@*[(инь 2 (инь 1 ()))(Ян 2 (инь 2 (инь 1 ())))];*[(инь 1 ())(Ян 2 (инь 2 (инь 1 ())))];@*[(инь 2 (инь 2 (инь 1 ())))(Ян 2 (инь 2 (инь 2 (инь 1 ()))))];*[(инь 2 (инь 1 ()))(Ян 2 (инь 2 (инь 2 (инь 1 ()))))];*[(инь 1 ())(Ян 2 (инь 2 (инь 2 (инь 1 ()))))];@*[(инь 2 (инь 2 (инь 2 (инь 1 ()))))(Ян 2 (инь 2 (инь 2 (инь 2 (инь 1 ())))))];...;...

Критика

Олег Киселев, автор продолжение с разделителями реализация для OCaml, и дизайнер интерфейс прикладного программирования (API) для манипулирования стеком с разделителями для реализации операторов управления, поддерживает использование ограниченные продолжения вместо продолжений полного стека, которыми манипулирует вызов / cc: "Предложение call / cc в качестве основной функции управления, с точки зрения которой должны быть реализованы все другие средства управления, оказывается плохой идеей. Производительность, утечки памяти и ресурсов, простота реализации , простота использования, легкость рассуждений - все возражают против call / cc. "[3]

Отношение к неконструктивной логике

В Переписка Карри – Ховарда между доказательствами и программами связывает вызов / cc к Закон Пирса, который расширяет интуиционистская логика к неконструктивному, классическая логика: ((α → β) → α) → α. Здесь ((α → β) → α) - тип функции ж, который может либо возвращать значение типа α напрямую, либо применять аргумент к продолжению типа (α → β). Поскольку существующий контекст удаляется при применении продолжения, тип β никогда не используется и может быть принят как ⊥, пустой тип.

Принцип исключение двойного отрицания ((α → ⊥) → ⊥) → α сравнимо с вариантом call-cc, который ожидает своего аргумента ж чтобы всегда оценивать текущее продолжение, обычно не возвращая значения. Внедрение классической логики в интуиционистскую логику связано с стиль прохождения продолжения перевод.[4]

Языки, реализующие call / cc

Смотрите также

Рекомендации

  1. ^ Дэвид Мадор, "вызов / cc ошеломляющий"
  2. ^ Инь Ван, «Понимание загадки Инь-Ян»
  3. ^ «Аргумент против звонка / cc».
  4. ^ Соренсен, Мортен Гейне; Уржичин, Павел (2007). «Классическая логика и операторы управления». Лекции об изоморфизме Карри-Ховарда (1-е изд.). Бостон, Массачусетс: Эльзевир. ISBN  0444520775.
  5. ^ "Подпись CONT". Стандартный ML Нью-Джерси. Bell Labs, Lucent Technologies. 1997-10-28. Получено 2019-05-15.
  6. ^ «Класс: Продолжение». Ruby-doc.org. Нейрогами, Джеймс Бритт. Получено 2019-05-15.
  7. ^ Ковальке, Оливер (2014). «Переключение контекста с вызовом / cc». Boost.org. Получено 2019-05-15.
  8. ^ https://stat.ethz.ch/R-manual/R-devel/library/base/html/callCC.html

внешняя ссылка

Статья основана на материалах, взятых из Бесплатный онлайн-словарь по вычислительной технике до 1 ноября 2008 г. и зарегистрированы в соответствии с условиями «перелицензирования» GFDL, версия 1.3 или новее.