执行以下呼叫/ cc表达式

问题描述 投票:1回答:2

我使用球拍,并得到以下简单代码的结果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中发现了internet的机制,其中说call/cc遵循以下四个步骤:

  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

请我做错了。我对延续的概念感到困惑。谢谢。

scheme racket evaluation continuations callcc
2个回答
0
投票

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

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


((1)另一个引起混淆的原因是,以连续传递样式“ continuations”调用函数参数。它们是not;它们是在这种或那种情况下被“调用”的简单函数,因此在描述上它们也被称为“连续”。

另请参见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(在翻译过程中,代码行按其编写的顺序编号)。


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)))
© www.soinside.com 2019 - 2024. All rights reserved.