有人可以用简单的话解释 call/cc 吗? [英] Could someone explain call/cc in simple words?

查看:40
本文介绍了有人可以用简单的话解释 call/cc 吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究语言球拍并试图了解 call/cc 的实际用途.有人可以用简单的话解释一下并举一两个例子吗?谢谢.

I am studying the language racket and trying to grasp what call/cc is actually for. Could someone please explain it in simple words and give an example or two? Thanks.

推荐答案

如果你有一个表达式 (+ (* 2 3) (/10 2)) 一个 Scheme 系统不会在同时但部分.Scheme 中没有指定顺序,但让我们想象一下它是从左到右的(我认为 Racket 总是从左到右):

If you have an expression (+ (* 2 3) (/ 10 2)) a Scheme system will not evaluate everything at the same time but in parts. The order is not specified in Scheme but lets imagine it's from left to right (I think Racket always do left to right):

你做(* 2 3),接下来就是计算(/10 2),然后(+ result1 result2).Scheme 系统可以通过在执行之前将您的代码转换为继续传递风格来实现这一点.上面的表达式变成了这样:

You do (* 2 3), the continuation to that would be to compute (/ 10 2), then (+ result1 result2). The way a Scheme system can do this is by transforming your code to Continuation passing style before execution. The expression above turns into something like this:

 (lambda (k)
  (*& 2 
      3
      (lambda (result1)
        (/& 10
            2
            (lambda (result2)
              (+& result1 result2 k))))))

现在,以 & 结尾的过程与 Scheme 中的相同,只是它需要一个延续作为最后一个参数.其中之一的示例:(define (+& a b k) (k (+ a b))).所有其他的都是这样做的,被认为是原始的.

Now, the procedures with & in the end are the same as in Scheme except it takes a continuation as it's last argument. An example of one of these: (define (+& a b k) (k (+ a b))). All the others are done just like that and are considered primitives.

如果您应用它并传递 displayvalues 它将显示或计算为 11.但是,如果您使用了 call/cc,您可以覆盖它.想象一下这个变体:

if you apply that and pass display or values it will either display or evaluate to 11. However, if you used call/cc you could override that. Imagine this variant:

(call/cc (lambda (k) (+ (* 2 3) (/ 10 (if (zero? a) (k +inf.0) a))

在 Scheme 中,除以零时会出错,如果发生这种情况,您想取消其余的计算并说结果是无限的.上面的代码就是这样做的,如果 a 为零,它不会对前两个计算的结果求和.它实际上充当了一个 GOTO.该代码的 CPS 版本将如下所示:

In Scheme you get an error when dividing with zero and if that happens you want to call off the rest of the calculations and say the result is infinite. The code above does that and if a is zero it won't sum the results from the two previous calculations.. It actually acts as a GOTO. A CPS version of that code would look something like this:

(lambda (k)
   (*& 2 
       3
       (lambda (result1)
         (zero?& a 
                 (lambda (azero?)
                   (if azero?
                       (k +inf.0) ; continuation used here
                       (/& 10
                           a
                           (lambda (result2)
                             (+& result1 result2 k))))))))) ; and here

那么 call/cc 有什么作用呢?好吧,它可以让您以通常的方式编写代码,而不是像计算机如何进行实际计算那样的 CPS,但是您可以通过掌握延续来获得两个世界的最佳效果,这样您就可以像在 CPS 中编写它一样做同样的事情.

So what does call/cc do? Well it lets you code your usual way and not CPS like how the computer does the actual computation but you get the best of two worlds by getting hold of the continuation so that you can do the same as if you had written it in CPS.

现在,想象一下这个代码块:

Now, imagine this code block:

(let* ((c 10)
       (r (call/cc (lambda (exit) exit))))
  (display "Hello\n")
  (cond ((zero? c) 'done)
        (else (set! c (- c 1))
              (r r))))

在这里你看到我将延续返回为 r.延续是从设置 r 开始的其余计算,然后执行 display ... 这实际上显示hello\n" 11 次,因为当你在底部它再次做同样的事情.

Here you see I return the continuation as r. The continuation is the rest of the calculations starting with setting r, then doing display ... This actually displays "hello\n" 11 times since when you call the continuation in the bottom it does the same all over again.

就像 eval 我确实尝试将其保持在绝对最小值,当我这样做时,我通常会这样做以从正在进行的计算中止.例如.

Just like eval I do try to keep this at an absolute minimum and when I do I usually do it to get an abort from a on going computation. Eg.

(define (lstadd1 lst)
  (call/cc (lambda (exit)
    (let loop ((lst lst))
       (cond ((pair? lst) (cons (add1 (car lst)) (loop (cdr lst))))
             ((null? lst) '())
             (else (exit #f))))))) ; not proper 

(lstadd1 '(1 2 3))   ; ==> (2 3 4)
(lstadd1 '(1 2 . 3)) ; ==> #f

有关更多示例 我喜欢 Matt Mights 页面 有很多关于如何使用延续的例子.

For more examples I love Matt Mights page with lots of examples on how to use continuations.

这篇关于有人可以用简单的话解释 call/cc 吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆