Вопрос

Это связано с Что такое call /cc?, но я не хотел использовать этот вопрос в своих целях, и некоторые из его аргументов, такие как аналогия с setjmp / longjmp, ускользают от меня.

Я думаю, у меня есть достаточное представление о том, что такое продолжение, я думаю о нем как о моментальном снимке текущего стека вызовов.Я не хочу вдаваться в дискуссию, почему это может быть интересно или что вы можете сделать с продолжениями.Мой вопрос более конкретен: почему я должен предоставлять аргумент функции для вызова / cc?Почему вызов /cc просто не возвращает текущее продолжение, чтобы я мог делать с ним все, что мне заблагорассудится (сохранить его, вызвать его, вы называете его)?В ссылке из этого другого вопроса (http://community.schemewiki.org/?call-with-current-continuation-for-C-programmers), в нем говорится о "По сути, это просто чистый способ передать вам продолжение и избежать последующих переходов обратно к сохраненной точке"., но я этого не понимаю.Это кажется излишне сложным.

Это было полезно?

Решение 4

Вопреки общепринятому сетевому этикету SO, я отвечаю на свой собственный вопрос, но скорее как редактор, чем как поставщик ответа.

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

Один из Постеры в LtU написал:

"Вы можете точно видеть, как call / cc позволяет вам "держаться в стороне". С помощью em или get / cc вам нужно выполнить какой-то тест, чтобы определить, есть ли у вас обратный переход или просто начальный вызов.По сути, call /cc исключает использование продолжения из продолжения, тогда как с get / cc или em продолжение содержит его использование, и поэтому (обычно) вам нужно добавить тест в начало продолжения (т.Е.сразу после get/cc / em), чтобы отделить "использование частей продолжения" от "остальных частей продолжения"."

Это привело меня домой.

В любом случае, спасибо вам, ребята!

Другие советы

Если вы используете конструкцию, подобную Jay shows, то вы можете захватить продолжение, но в некотором смысле захваченное значение уже испорчено, потому что вы уже находитесь внутри этого продолжения.В отличие, call/cc может быть использован для захвата продолжения, которое все еще ожидающий выполнения за пределами текущего выражения.Например, одним из простейших применений продолжений является реализация своего рода abort:

(call/cc (lambda (abort)
           (+ 1 2 (abort 9))))

Вы не можете сделать это с помощью операции, которую вы описываете.Если вы попробуете это:

(define (get-cc) (call/cc values))
(let ([abort (get-cc)]) (+ 1 2 (abort 9)))

затем вы получите сообщение об ошибке подачи заявки 9 как процедура.Это происходит потому, что abort перескакивает обратно к let с новым значением 9 -- что означает, что сейчас вы выполняете второй раунд того же выражения сложения, за исключением того, что теперь abort связан с 9...

Два дополнительных сопутствующих примечания:

  1. Хорошее практическое введение в продолжения см. ПЛАЙ.
  2. call/cc является немного сложный в том смысле, что он принимает функцию - концептуально более простая в использовании конструкция - это let/cc который вы можете найти в некоторых реализациях, таких как PLT Scheme.Приведенный выше пример становится (let/cc abort (+ 1 2 (abort 9))).

Это было бы менее универсально.Если вы хотите такого поведения, вы можете просто сделать:

(call/cc (lambda (x) x))

Вы могли бы взглянуть на примеры использования продолжений в книге "Даррелл Фергюсон и Дуайт Дуго."Вызов с текущими шаблонами продолжения".8-я конференция по шаблонным языкам программ.Сентябрь 2001 года". (http://library.readscheme.org/page6.html) и попробуйте переписать их, используя call/cc-return, определенный как указано выше.

Я предлагаю начать с того, что задам себе вопрос:что значит быть первоклассным продолжением?

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

call /cc - особенно элегантный способ реализовать эту идею:текущее продолжение упаковано как процедура, которая инкапсулирует то, что нужно сделать с выражением, как то, что процедура делает при применении к выражению;представление продолжения таким образом просто означает, что закрытие этой процедуры содержит среду на сайте, на котором она была вызвана.

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

На прощание рассмотрим реализацию let / cc, о которой упоминал Эли, которую я предпочитаю называть bind / cc:

(define-syntax bind/cc
    (syntax-rules ()
        ((bind/cc var . body)
             (call/cc (lambda (var) . body)))))

И в качестве упражнения, как бы вы реализовали call / cc на основе bind / cc?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top