Особенности звонка / куб. - PullRequest
7 голосов
/ 13 июля 2009

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

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

Ответы [ 4 ]

9 голосов
/ 14 июля 2009

Если вы используете такую ​​конструкцию, как показывает Джей, вы можете получить продолжение, но в некотором смысле полученное значение уже испорчено, потому что вы уже внутри этого продолжения. Напротив, 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))).
2 голосов
/ 08 декабря 2009

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

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

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

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

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

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

2 голосов
/ 04 декабря 2009

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

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

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?

2 голосов
/ 13 июля 2009

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

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

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

...