因此,我试图弄清楚Scheme中的整个call/cc
事物。以下是我正在使用的代码:
(+ 1 (call/cc
(lambda (k)
(if (number? k)
(call/cc (lambda (k) (k (- 1 k))))
(k 4)))))
所以我们在这里开始在第一个括号中添加两个参数。 1
以及由于热切评价我们必须评估的其余部分。所以我们有一个call/cc
接受一个参数,一个函数,call/cc
通过调用来评估。 (我是对的吗?)与此同时,它在我们的第一个括号中保留了迄今为止发生的其余部分,即(+ 1 [])
,这是“延续”。 (我是对的?)所以我们将lambda k
称为继续,如我刚才所述,(+ 1 [])
。在函数中它然后询问这是否是一个数字,它不是并且是“然后”。我在这里“迷失”了,这第二个call/cc
做了什么?调用(k 4)
是什么,使整个事情评估为5
?
答案 0 :(得分:3)
你很亲密!我认为你的所有问题都是正确的。
传递给call/cc
的函数接受一个参数(在您的示例中为k
),这是一种将值返回到当前延续的方法。 k
是一个参数的函数。当您使用某个值调用该函数时,该值将返回并代替_
中的(+ 1 _)
。
因此,在您的示例中,(number? k)
永远不会成立,并且永远不会执行对call/cc
的第二次调用。 (即使它是,它会因运行时错误而失败,其中(- 1 k)
从1中减去一个函数。)因此它实际执行“else”分支:(k 4)
,它返回4到{{1}所以结果是5。
希望这很清楚!
答案 1 :(得分: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
的范围。
k
这是一个第一类值(当然,因为它被命名)。 Scheme运行时系统将在幕后自动为其分配(call/cc ...)
呼叫点的延续。对于程序员,只要我们有权访问它,我们就可以使用它。
延续是一个参数的函数。当调用该函数时,它会将其参数传递给continuation的调用上下文。但由于k
是一流的命名值,我们可以自由传递它。 “内部”代码可以像我们想要的那样复杂,它可以调用其他地方定义的其他函数等。如果它将k
作为参数传递给这样的外部函数,它也可以使用它。
使用值调用k
表示将该值返回到原始(call/cc ...)
调用的调用上下文中。的 直接 即可。就像longjmp
那样(除了我们可以在那里返回任何值,而不仅仅是int
)。