【问题标题】:What is the continuation of call/cc in a let blocklet 块中 call/cc 的延续是什么
【发布时间】:2017-01-22 09:59:37
【问题描述】:

我遇到了一个使用 call/cc 解释 Continuations 的 sn-p。在下面提供的 sn-p 中,由 call/cc 调用的 fn 的延续是整个 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)

【问题讨论】:

    标签: scheme racket continuations callcc


    【解决方案1】:

    实现将整个内容重写为继续传递样式 (=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 中编写它。当你知道它是如何工作的时候,它并没有太多的魔力。

    【讨论】:

      【解决方案2】:

      call/cc 表达式的延续包括 call/cc 表达式之后的表达式。 如果我们添加(displayln "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
      

      【讨论】:

      • 我从示例中推断出这一点。在(+ 1 (call/cc (lambda (k) (k 2))) 3) 中,延续是(fn [v] (+ 1 v 2))。但在(let (bindings) 的情况下,延续是调用/cc 之后的语句状态。我猜(而且我认为我是对的)可以将 let(绑定)重写为 lambda (),其中的代码位于 do 块中,因此延续实际上是 call/cc之后的语句集>
      猜你喜欢
      • 2016-01-18
      • 2011-02-16
      • 2019-12-30
      • 2016-06-05
      • 2019-12-17
      • 2011-08-25
      • 1970-01-01
      • 2014-09-02
      相关资源
      最近更新 更多