如何在Racket中使用带有call/cc的标记提示?

huangapple go评论61阅读模式
英文:

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-continuationcall-with-composable-continuation来定义call/cc的方式。(警告:我还没有测试过,所以可能会有错误。)在下面的类型注释中,我使用以下约定:P是与提示标签相关联的结果类型,Acall/cccall/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/ccdynamic-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.

huangapple
  • 本文由 发表于 2020年1月3日 20:32:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/59578709.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定