Понимание неограниченных продолжений - PullRequest
2 голосов
/ 20 мая 2011

Предположим, у меня есть следующий код (в C-подобном синтаксисе):

void foo(int arg) { ... }

int bar() {
...
// call with continuation 
...
}

foo ( bar() )
// after foo invocation

1) Функция foo вызывает функцию bar, которая работает, пока не достигнет строки с call with continuation.

2) В этой строке создается функция continuation.Он представляет остальную часть bar и foo.Функция continuation передается в качестве аргумента функции call with continuation.

3) Функция call with continuation делает с аргументом все, что ей нужно (например, она может просто храниться в глобальной переменной), и возвращает.

4) Как только возвращается call with continuation, мы сразу же переходим к строке с «after foo invocation», а остальные bar и foo не выполняются.

5) ВЧтобы продолжить выполнение bar и foo, мы должны явно вызвать функцию continuation (созданную в (2) и, вероятно, сохраненную в (3)).После вызова функции continuation выполнение продолжается сразу после call with continuation.

. Это правильно?Я что-то упускаю из неограниченных продолжений?

1 Ответ

4 голосов
/ 20 мая 2011

Нет. Как правило, неограниченные продолжения (например, созданные с помощью call/cc схемы) переходят при вызове continuation, а не при вызове call/cc (он же call-with-current-continuation).

Итак, конкретизируйте ваш пример:

continuation savedk;

void foo(int arg) { ... }

int bar() {
  ...
  call/cc(handler)
  // after call/cc
  println "after call/cc"
  ...
}

void handler(continuation k) {
  savedk = k
}

foo ( bar() )
// after foo invocation
  1. Выполнение начинается. Мы вводим bar (мы еще не ввели foo; мы сделаем это, когда закончим с bar).

  2. Когда мы нажимаем на вызов call/cc в bar, «программный контекст» превращается в объект, называемый продолжением. На этом этапе контекст программы состоит из «завершить выполнение bar, затем вызвать foo для результата, а затем выполнить все, что придет после вызова foo». Продолжение передается функции, указанной в качестве аргумента call/cc, что в моем примере handler.

  3. handler что-то делает с продолжением. Давайте предположим, что он хранит его в глобальной переменной. Затем он возвращается к точке сразу после вызова call/cc, все еще внутри bar.

  4. Допустим, мы распечатаем что-то на этом этапе. Затем bar заканчивается, и мы называем foo, и это заканчивается.

  5. Если мы теперь применим продолжение в savedk, управление переходит обратно в bar и восстанавливает контекст программы до «завершения выполнения bar», затем вызывает foo для результата и затем делает все, что угодно приходит после foo вызова ". Таким образом, мы получаем еще одну строку. На самом деле, если мы не очистим переменную savedk или не протестируем какое-либо другое состояние, мы можем получить бесконечный цикл, если «сделать все, что придет после вызова foo», снова вызвать savedk!

...