Какое продолжение call / cc в блоке let

Я наткнулся на отрывок, объясняющий продолжение с помощью call / cc. Во фрагменте, приведенном ниже, какое продолжение для fn, вызываемого call / cc, - это весь блок let или строки под call / cc? Также может кто-нибудь объяснить, почему весь let-блок не предоставляется в качестве продолжения?

#lang racket
(define resume-test-3 #f)

(define test-3 (lambda ()
   ; the let defines a variable i local to the lambda, and 
   ; sets its value to 0
   (let ((i 0))
     ;
     (call/cc (lambda (k) (set! resume-test-3 k)))
     ;
     ; The next time the-continuation is called, we start here.
     (displayln "I am back ")
     (set! i (+ i 1))
     ; and return the value i
     i
     )
    ))

(test-3)
(resume-test-3)
(resume-test-3)

person draklor40    schedule 14.09.2016    source источник


Ответы (2)


Продолжение выражения call/cc состоит из выражений после выражения call/cc. Если мы добавим (displayln "Entering let"), мы увидим, что при вызове продолжения не выводится «Entering let».

#lang racket
(define resume-test-3 #f)

(define test-3 (lambda ()
   ; the let defines a variable i local to the lambda, and 
   ; sets its value to 0
   (let ((i 0))
     (displayln "Entering let")
     ;
     (call/cc (lambda (k) (set! resume-test-3 k)))
     ;
     ; The next time the-continuation is called, we start here.
     (displayln "I am back ")
     (set! i (+ i 1))
     ; and return the value i
     (displayln "Leaving let")
     i)))

(test-3)
(resume-test-3)
(resume-test-3)

Вывод:

Entering let
I am back 
Leaving let
1
I am back 
Leaving let
2
I am back 
Leaving let
3
person soegaard    schedule 14.09.2016
comment
Я сделал вывод из примера. В (+ 1 (call/cc (lambda (k) (k 2))) 3) продолжение - (fn [v] (+ 1 v 2)). Но в случае (let (bindings) продолжением является состояние операторов после вызова / cc. Я думаю (и я думаю, что я прав) let (bindings) можно переписать как lambda () с кодом внутри него в блоке do, поэтому продолжение фактически представляет собой набор операторов после call / cc - person draklor40; 15.09.2016

Реализации переписывают все это в стиле передачи продолжения (= CPS):

(define resume-test-3-cps #f)
(define test-3-cps
  (lambda (k)
    ((lambda (kl i) ; this is the "let"
       ((lambda (tk1) (tk1 (set! resume-test-3-cps tk1)))
        (lambda (not-used)
          ((lambda (tk2) (tk2 (displayln "I am back ")))
           (lambda (not-used)
             ((lambda (tk3) (tk3 (set! i (+ i 1))))
              (lambda (not-used)
                ((lambda (tk4) (tk4 (displayln "Leaving let")))
                 (lambda (not-used)
                   ((lambda (tk5) (tk5 i))
                    kl))))))))))
     k 0))) ; variables to "let"

;; top level have barriers, don't know how to simulate them
;; doing full CPS here will make an infinite loop
(test-3-cps values)
(resume-test-3-cps values)
(resume-test-3-cps values)

Обратите внимание, что это работает даже без использования call/cc. Это потому, что call/cc - это всего лишь способ получить возможности CPS без необходимости писать его в CPS. Когда знаешь, как это работает на самом деле, не так уж много волшебства.

person Sylwester    schedule 14.09.2016