我使用球拍,并得到以下简单代码的结果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
遵循以下四个步骤:
C
,并使用该参数值应用当前延续。expr
---即,它调用(expr C)
。(expr C)
调用expr
,否则返回计算C
的结果,在这种情况下,将返回传递给C
的值。因此,对于第一个call/cc
,我按照上述步骤操作:
C
指(λ (x) x)
。由于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))
要返回上述代码的结果值,请在球拍中执行以上操作。
但是,以上代码(由我修改)未执行,并产生错误:
> application: not a procedure; > > expected a procedure that can be applied to arguments > > given: 4 > > arguments...: > > 3
请我做错了。我对延续的概念感到困惑。谢谢。
延续不仅是闭包(函数)。他们还对代码中的定义位置执行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(在翻译过程中,代码行按其编写的顺序编号)。
[当解释器看到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)))