Как этот итератор списка схем использует call-with-current-continue? - PullRequest
4 голосов
/ 12 апреля 2011

Я пытаюсь прочитать этот код:

(define list-iter
  (lambda (a-list)
    (define iter
      (lambda ()
        (call-with-current-continuation control-state)))
    (define control-state
      (lambda (return)
        (for-each
          (lambda (element)
            (set! return (call-with-current-continuation
                           (lambda (resume-here)
                             (set! control-state resume-here)
                             (return element)))))
          a-list)
        (return 'list-ended)))
    iter))

Может кто-нибудь объяснить, как call-with-current-continuation работает в этом примере?

Спасибо

Ответы [ 3 ]

3 голосов
/ 12 апреля 2011

Суть call-with-concurrent-continuation, или сокращенно call/cc, заключается в возможности захвата контрольных точек или продолжений во время выполнения программы. Затем вы можете вернуться к этим контрольным точкам, применив их как функции.

Вот простой пример, где продолжение не используется:

> (call/cc (lambda (k) (+ 2 3)))
5

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

> (call/cc (lambda (k) (+ 2 (k 3))))
3
> (+ 4 (call/cc (lambda (k) (+ 2 3))))
9
> (+ 4 (call/cc (lambda (k) (+ 2 (k 3)))))
7

Когда вызывается продолжение, поток управления возвращается туда, где продолжение было захвачено call/cc. Думайте о выражении call/cc как о дыре, которая заполняется тем, что передается k.

list-iter - значительно более сложное использование call/cc, и его может быть трудно начать использовать. Во-первых, вот пример использования:

> (define i (list-iter '(a b c)))
> (i)
a
> (i)
b
> (i)
c
> (i)
list-ended
> (i)
list-ended

Вот эскиз того, что происходит:

  1. list-iter возвращает процедуру без аргументов i.
  2. Когда вызывается i, мы немедленно получаем продолжение и передаем его control-state. Когда это продолжение, связанное с return, будет вызвано, мы немедленно вернемся к тому, кто вызвал i.
  3. Для каждого элемента в списке мы берем новое продолжение и переписываем определение control-state этим новым продолжением, что означает, что мы возобновим оттуда в следующий раз, когда появится шаг 2.
  4. После установки control-state в следующий раз мы передаем текущий элемент списка обратно в продолжение return, получая элемент списка.
  5. Когда i вызывается снова, повторяйте с шага 2, пока for-each не выполнит свою работу для всего списка.
  6. Вызвать продолжение return с помощью 'list-ended. Поскольку control-state не обновляется, он будет возвращать 'list-ended каждый раз, когда вызывается i.

Как я уже сказал, это довольно сложное использование call/cc, но я надеюсь, что этого достаточно, чтобы пройти через этот пример. Для более мягкого введения в продолжения, я бы порекомендовал подобрать Закаленный мошенник .

0 голосов
/ 27 июня 2015

Это по сути:

(define (consume)
  (write (call/cc control)))

(define (control ret)
   (set! ret (call/cc (lambda (resume)
                        (set! control resume)
                        (ret 1))))
   (set! ret (call/cc (lambda (resume)
                        (set! control resume)
                        (ret 2))))
   (set! ret (call/cc (lambda (resume)
                        (set! control resume)
                        (ret 3)))))

(consume)
(consume)
(consume)

Надеюсь, это легче понять.

0 голосов
/ 12 апреля 2011

Обычно она принимает функцию f в качестве параметра и применяет f к текущему контексту / состоянию программы.

Из википедии:
(define (f return)
(return 2)
3)

(display (f (lambda (x) x))) ; displays 3

(display (call-with-current-continuation f)) ; displays 2

Таким образом, в основном, когда f вызывается без продолжения по току (cc), функция применяется к2, а затем возвращает 3. При использовании текущего продолжения параметр применяется к 2, что заставляет программу перейти к точке, в которой было вызвано текущее продолжение, и, таким образом, возвращает 2. Его можно использовать для генерации возвратов,или приостановить выполнение потока.

Если вы знаете C, подумайте об этом так: в C вы можете взять указатель на функцию.У вас также есть механизм возврата.Предположим, что возвращаемое значение принимает параметр того же типа, что и функция.Предположим, что вы можете взять его адрес и сохранить этот адрес в переменной или передать его в качестве параметра и разрешить функциям возвращаться за вас.Он может использоваться для имитации броска / вылова или в качестве механизма для сопрограмм.

...