执行以下 call/cc 表达式

Execute the following call/cc expression

我使用球拍并通过以下简单代码得到了结果4

(let/cc done
  ((let/cc esc
     (done (+ 1 (let/cc k
                  (esc k)))))
   3))

我打算一步步执行这段代码。

首先,我把第一个let/cc改成了下面的call/cc形式:

(call/cc (λ (done)
           ((let/cc esc
              (done (+ 1 (let/cc k
                           (esc k)))))
            3)))

当然,这也会产生 4

其次,由于我在 internet 中找到了 call/cc 的机制,其中 call/cc 执行以下 4 个步骤:

  1. 捕获当前的延续。
  2. 构造一个接受一个参数的函数C,并将当前延续应用到该参数值。
  3. 将此函数作为参数传递给 expr --- 即,它调用 (expr C).
  4. Returns 评估 (expr C) 的结果,除非 expr 调用 C,在这种情况下传递给 C 的值是 returned.

因此,对于第一个 call/cc,我按照上述步骤操作,例如:

  1. 当前延续是一个身份。
  2. C 指的是 (λ (x) x).
  3. 因为expr(λ (done) ((let/cc esc (done (+ 1 (let/cc k (esc k))))) 3))(expr C)是:

    ((λ (done)
       ((let/cc esc
          (done (+ 1 (let/cc k
                       (esc k)))))
        3))
     (λ (x) x))
    
  4. 到return以上代码的结果值,我在racket上面执行

但是,上面的代码(由我修改)没有执行并产生错误:

> application: not a procedure;
>
> expected a procedure that can be applied to arguments
>
>  given: 4
>
>  arguments...:
>
>   3

请问我做错了什么。我混淆了延续的概念。谢谢

当解释器看到 call/cc 时,即使不执行 CPS 的解释器也会使用该子树执行它。您的代码看起来像这样:

((λ (done)
   ((λ (esc)      
      ((λ (k) (esc k))
       (λ (r) (k+ done 1 r))))
    (λ (v) (v 3))))
 values)


; k+ implementation (+, but CPS) 
(define (k+ k . args)
  (k (apply + args)))

延续不仅仅是闭包(函数)。他们还执行跳转 到他们在代码中定义的位置。您必须完全执行 CPS 转换才能尝试在 Scheme 解释器中评估结果表达式。该表达式将只包含 lambdas 而没有延续(在 call/cc (1) 的意义上)。

您尝试的表达式混合了它们 - 它将 done 定义为简单的 lambda 定义函数,但它仍然在嵌套上下文中用作延续。


(1)(另一个混淆来源是以连续传递样式 "continuations" 调用函数参数。它们是 不是 "true" continuations;它们是简单的函数 "to be called" 在这种或那种情况下,所以通俗地说它们也被称为 "continuations" 虽然 "contingencies" 甚至 "handlers" 可能会更好。)

另见 another example of call/cc code translation

按照这种方法,将您的 Scheme 代码翻译成 Common Lisp,我们得到:

;; (let/cc done
;;   ((let/cc esc
;;      (done (+ 1 (let/cc k
;;                   (esc k)))))
;;    3)) 
(prog  (retval done arg1 func esc arg2 k arg3 arg4)
    (setq done (lambda (x) (setq retval x) (go DONE)))    ; 3
     (setq arg1 3)                                        ; 5
      (setq esc  (lambda (x) (setq func x) (go ESC)))     ; 8
       (setq arg3 1)                                      ; 10
        (setq k  (lambda (x) (setq arg4 x) (go K)))       ; 12
        (setq arg4 (funcall esc k))                       ; 13
  K                                                       ; 11  continuation K
       (setq arg2 (+ arg3 arg4))                          ; 9
      (setq func (funcall done arg2))                     ; 7
  ESC                                                     ; 6   continuation ESC
     (setq retval (funcall func arg1))                    ; 4
  DONE                                                    ; 2   continuation DONE
    (return retval))                                      ; 1

确实returns 4(在翻译过程中,代码行按编写时的顺序编号)。