执行以下 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 个步骤:
- 捕获当前的延续。
- 构造一个接受一个参数的函数
C
,并将当前延续应用到该参数值。
- 将此函数作为参数传递给
expr
--- 即,它调用 (expr C)
.
- Returns 评估
(expr C)
的结果,除非 expr
调用 C
,在这种情况下传递给 C
的值是 returned.
因此,对于第一个 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))
到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 解释器中评估结果表达式。该表达式将只包含 lambda
s 而没有延续(在 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(在翻译过程中,代码行按编写时的顺序编号)。
我使用球拍并通过以下简单代码得到了结果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 个步骤:
- 捕获当前的延续。
- 构造一个接受一个参数的函数
C
,并将当前延续应用到该参数值。 - 将此函数作为参数传递给
expr
--- 即,它调用(expr C)
. - Returns 评估
(expr C)
的结果,除非expr
调用C
,在这种情况下传递给C
的值是 returned.
因此,对于第一个 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))
到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 解释器中评估结果表达式。该表达式将只包含 lambda
s 而没有延续(在 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(在翻译过程中,代码行按编写时的顺序编号)。