1

我使用球拍,我得到了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也产生了。

其次,因为我call/cc互联网上找到了说call/cc做以下4个步骤的机制:

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

因此,我首先按照上述步骤进行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. 为了返回上面代码的结果值,我在上面执行了球拍。

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

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

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

4

2 回答 2

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)))
于 2015-12-16T09:03:44.030 回答
0

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

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


(1)(另一个混淆的来源是调用函数参数以连续传递风格“延续”。它们不是“真正的”延续;它们是在这种或那种可能性中“被调用”的简单函数,所以通俗地说它们是也称为“延续”,尽管“意外事件”甚至“处理程序”可能更好。)

另请参阅call/cc 代码翻译的另一个示例

按照这种方法,将您的 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

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

于 2015-12-16T14:43:47.000 回答