2

因此,我试图call/cc在 Scheme 中弄清楚这一切。以下是我正在使用的代码:

(+ 1 (call/cc
  (lambda (k)
    (if (number? k)
        (call/cc (lambda (k) (k (- 1 k))))
        (k 4)))))

所以在这里我们开始在第一个括号中添加两个参数。1其余的我们必须评估,因为急切的评估。所以我们有一个call/cc接受一个参数的函数,一个函数,它call/cc通过调用来评估。(我说的对吗?)同时它包含了到目前为止在我们的第一个括号中发生的其余部分,即(+ 1 []),它是“延续”。(我说的对吗?)所以我们k用我刚才描述的延续来调用 lambda (+ 1 []),. 然后在函数中询问这是否是一个数字,它不是并且执行“then”。我在这里“迷路”了,这一秒call/cc做什么?调用什么(k 4)来使整个事情评估为5

4

2 回答 2

4

你很接近!我认为你所有的问题都是对的。

您传递给的函数call/cc接受一个参数(k在您的示例中),这是一种将值返回到当前延续的方法。k是一个参数的函数。当您使用值调用该函数时,该值将返回并代替_in this: (+ 1 _)

因此,在您的示例中,(number? k)永远不会正确,并且永远不会执行第二次调用call/cc。(即使是这样,它也会因运行时错误而失败,(- 1 k)从 1 中减去一个函数。)所以它实际上执行了“else”分支:(k 4),它返回 4,(+ 1 4)所以结果是 5。

希望这很清楚!

于 2012-07-25T02:43:10.070 回答
1

call/cc就像setjmp。它定义了一个退出点,后面的代码可以直接“跳转”到,就像这样longjmp做。

它遵循一定的协议,所以我们总是写

( .... surrounding code .....
   (call/cc (lambda (k)
      .... inner code which has access to the exit point "k" ....
      )) .... more surrounding code .... )

在该协议下,“内部”代码照常执行,但k在其范围内也有一个名称。“周围的”代码都无法访问它,因为它超出了k's 的范围。

k这是一个一流的值(当然,正如它的名字一样)。(call/cc ...)Scheme 运行时系统将在幕后自动为其分配调用点的延续。对于程序员来说,只要我们可以访问它,我们就可以使用它。

延续是一个参数的函数。当调用该函数时,它会将其参数传递给延续的调用上下文。但既然k是一等的命名值,我们可以自由地传递它。“内部”代码可以像我们想要的那样复杂,它可以调用其他地方定义的其他函数等。如果它k作为参数传递给这样的外部函数,它也可以使用它。

使用值调用k意味着将该值返回到原始(call/cc ...)调用的调用上下文中。直接。就像longjmping 那里(除了我们可以在那里返回任何值,而不仅仅是int)。

于 2012-07-29T07:59:18.590 回答