执行以下call / cc exp

时间:2015-12-15 20:46:52

标签: scheme racket continuations

我使用了球拍,我得到了结果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,并将当前的continuation应用于该参数值。
  3. 将此函数作为参数传递给expr ---即调用(expr C)
  4. 返回评估(expr C)的结果,除非expr调用C,在这种情况下,将返回传递给C的值。
  5. 因此,我按照第一个call/cc的上述步骤进行了操作:

    1. 目前的继续是一种身份。
    2. C指的是(λ (x) x)
    3. 由于expr(λ (done) ((let/cc esc (done (+ 1 (let/cc k (esc k))))) 3))(expr C)为:
    4. ((λ (done)
         ((let/cc esc
            (done (+ 1 (let/cc k
                         (esc k)))))
          3))
       (λ (x) x))
      
      1. 要返回上述代码的结果值,我在球拍上执行。
      2. 但是,上面的代码(由我修改)不会执行并产生错误:

          

        申请:不是程序;

             

        期望一个可以应用于参数的过程

             给出:4

             

        ...参数:

             

        3

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

2 个答案:

答案 0 :(得分:1)

当口译员看到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)))

答案 1 :(得分:0)

Continuations不仅仅是闭包(函数)。他们还在代码中执行 jump 到他们的定义位置。您必须完整执行CPS转换以尝试在Scheme解释器中评估结果表达式。该表达式仅包含lambda s且没有延续(在call/cc (1) 的意义上)。

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

(1)另一个混乱的来源是在继续传递样式“continuations”中调用函数参数。它们 ;它们是在这种或那种可能性中“被称为”的简单功能,因此描述性地它们也被称为“延续”。

另见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
       (setq arg2 (+ arg3 arg4))                          ; 9
      (setq func (funcall done arg2))                     ; 7
  ESC                                                     ; 6
     (setq retval (funcall func arg1))                    ; 4
  DONE                                                    ; 2
    (return retval))                                      ; 1

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