Особенности звонка / куб.

Это связано с тем, что такое Call/ CC?, но я не хотел угонять этот вопрос для моих собственных целей, и некоторые из его аргументов, такие как аналогия с setjmp/longjmp, уклоняются от меня.

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

4 ответа

Решение

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

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

Один из плакатов в LtU писал:

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

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

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

Если вы используете такую ​​конструкцию, как показывает Джей, то вы можете получить продолжение, но в некотором смысле полученное значение уже испорчено, потому что вы уже внутри этого продолжения. По сравнению, 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. Хорошее практическое введение в продолжения смотрите в PLAI.
  2. call/cc является немного сложным в том смысле, что он принимает функцию - концептуально более легкая в использовании конструкция let/cc который вы можете найти в некоторых реализациях, таких как PLT Scheme. Приведенный выше пример становится (let/cc abort (+ 1 2 (abort 9))),

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

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

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

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

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

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

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

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

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

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

Другие вопросы по тегам