英文:
How to use tagged prompts with call/cc in Racket?
问题
第一个代码片段中的问题是,您在使用call-with-current-continuation
时创建了一个继续(continuation),然后尝试在稍后的地方(cc 4
)调用它,但在这之前,您尝试在不同的continuation prompt上调用它。具体来说,您在创建continuation时使用了自定义prompt标签pr
,然后尝试在默认prompt上调用它,这是不允许的。
默认情况下,call-with-continuation-prompt
创建的prompt是#f
,而call-with-current-continuation
也使用默认prompt。这是为了确保在continuation的上下文中调用它们之间的匹配。
因此,第一个代码片段中的调用(cc 4)
不会成功,因为它与之前创建的continuation prompt pr
不匹配。这就是为什么会引发异常的原因。
而在第二个和第三个代码片段中,您只使用了默认的continuation prompt,因此没有这个问题,代码可以正常工作。
英文:
Why this code
(let ([cc #f]
[pr (make-continuation-prompt-tag 'pr)])
(call-with-continuation-prompt
(λ () (displayln
(+ 2 (call-with-current-continuation
(λ (k) (set! cc k) 1)
pr))))
pr)
(cc 4))
(on Racket v7.5) raise exception?:
3
; continuation application: no corresponding prompt in the current continuation
; Context:
; /usr/share/racket/collects/racket/repl.rkt:11:26
While same code with default tag works as expected:
(let ([cc #f])
(call-with-continuation-prompt
(λ ()
(displayln (+ 2 (call-with-current-continuation
(λ (k) (set! cc k) 1))))))
(cc 4))
3
6
And same (as the first snippet) code with composable continuation
(let ([cc #f]
[pr (make-continuation-prompt-tag 'pr)])
(call-with-continuation-prompt
(λ () (displayln
(+ 2 (call-with-composable-continuation
(λ (k) (set! cc k) 1)
pr))))
pr)
(cc 4))
works as expected too:
3
6
What is wrong with the first snippet? Or what is wrong with my understanding?
答案1
得分: 3
从call-with-current-continuation的文档中:
> 如果将proc的继续参数应用于任何时候,那么它会删除当前继续的部分,直到最近由prompt-tag标记的提示(不包括提示;如果不存在这样的提示,将引发exn:fail:contract:continuation异常),...。
在你的第一个示例中,当你应用cc
时,在应用发生时,在上下文(“堆栈”上)中没有pr
的提示,因此它会引发异常。
第二个示例有效,因为默认标签始终有一个提示。
第三个示例有效,因为call-with-composable-continuation
创建一个不会中止当前继续的继续程序,因此它的应用没有前提条件。(这也是为什么它被认为是“可组合”的继续的一部分。)
如果有帮助的话,以下是大致如何使用abort-current-continuation
和call-with-composable-continuation
来定义call/cc
的方式。(警告:我还没有测试过,所以可能会有错误。)在下面的类型注释中,我使用以下约定:P
是与提示标签相关联的结果类型,A
是call/cc
或call/comp
调用的结果类型,也是继续的参数的类型。⊥
是空类型;它实际上表示“不返回”。
;; call-with-continuation-prompt : (-> P) PromptTag[P] -> P
;; 仅允许默认的中止处理程序!
;; abort-current-continuation : PromptTag[P] (-> P) -> ⊥
;; 假设默认的中止处理程序!
;; call-with-composable-continuation : ((A -> P) -> A) PromptTag[P] -> A
;; call/cc : ((A -> ⊥) -> A) PromptTag[P] -> A
(define (call/cc proc tag)
(call-with-composable-continuation
(lambda (ck) ;; ck : A -> P
;; k : A -> ⊥
(define (k v)
(abort-current-continuation tag
(lambda () (ck v)))))
tag))
这个定义不考虑call/cc
与dynamic-wind
的实际交互方式,它不适用于自定义提示处理程序,并且它不考虑多个返回值(对应于多个继续参数),但它应该给你一个关于call/cc
正在做什么的大致概念。特别是,对abort-current-continuation
的调用要求当前继续具有带有tag
标记的提示。
英文:
From the docs for call-with-current-continuation:
> If the continuation argument to proc is ever applied, then it removes the portion of the current continuation up to the nearest prompt tagged by prompt-tag (not including the prompt; if no such prompt exists, the exn:fail:contract:continuation exception is raised), ....
In your first example, when you apply cc
, there is no prompt for pr
in the context ("on the stack") when the application occurs, so it raises an exception.
The second example works because there is always a prompt for the default tag.
The third example works because call-with-composable-continuation
creates a continuation procedure that does not abort the current continuation, so there is no precondition for its application. (That's part of why it's considered a "composable" continuation.)
If it helps, here is approximately how call/cc
can be defined in terms of the abort-current-continuation
and call-with-compposable-continuation
. (Warning: I haven't tested this, so there may be bugs.) In the type annotations below, I use the following conventions: P
is the result type associated with a prompt tag and A
is the result type of a call/cc
or call/comp
call, which is also the type of the continuation's argument. ⊥
is the empty type; it effectively means "doesn't return".
;; call-with-continuation-prompt : (-> P) PromptTag[P] -> P
;; Only allows default abort handler!
;; abort-current-continuation : PromptTag[P] (-> P) -> ⊥
;; Assumes the default abort handler!
;; call-with-composable-continuation : ((A -> P) -> A) PromptTag[P] -> A
;; call/cc : ((A -> ⊥) -> A) PromptTag[P] -> A
(define (call/cc proc tag)
(call-with-composable-continuation
(lambda (ck) ;; ck : A -> P
;; k : A -> ⊥
(define (k v)
(abort-current-continuation tag
(lambda () (ck v))))
(proc k))
tag))
This definition doesn't account for how call/cc
actually interacts with dynamic-wind
, it doesn't work with custom prompt handlers, and it doesn't account for multiple return values (which correspond to multiple continuation arguments), but it should give you a rough idea of what call/cc
is doing. In particular, the call to abort-current-continuation
requires that the current continuation has a prompt tagged with tag
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论