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
Смотрите также
Рекомендации
- ^ Дэвид Мадор, "вызов / cc ошеломляющий"
- ^ Инь Ван, «Понимание загадки Инь-Ян»
- ^ «Аргумент против звонка / cc».
- ^ Соренсен, Мортен Гейне; Уржичин, Павел (2007). «Классическая логика и операторы управления». Лекции об изоморфизме Карри-Ховарда (1-е изд.). Бостон, Массачусетс: Эльзевир. ISBN 0444520775.
- ^ "Подпись CONT". Стандартный ML Нью-Джерси. Bell Labs, Lucent Technologies. 1997-10-28. Получено 2019-05-15.
- ^ «Класс: Продолжение». Ruby-doc.org. Нейрогами, Джеймс Бритт. Получено 2019-05-15.
- ^ Ковальке, Оливер (2014). «Переключение контекста с вызовом / cc». Boost.org. Получено 2019-05-15.
- ^ https://stat.ethz.ch/R-manual/R-devel/library/base/html/callCC.html
внешняя ссылка
- Краткое введение в
вызов с текущим продолжением
- Значение
вызов с текущим продолжением
в спецификации схемы - Юмористическое объяснение вызов с текущим продолжением от Роба Варнока из Usenet's comp.lang.lisp
- Совместная многозадачность на схеме с использованием Call-CC
Статья основана на материалах, взятых из Бесплатный онлайн-словарь по вычислительной технике до 1 ноября 2008 г. и зарегистрированы в соответствии с условиями «перелицензирования» GFDL, версия 1.3 или новее.