有没有人对如何运作有一个很好的指导?带有视觉辅助工具的东西会很好,我遇到的所有指南似乎都说同样的东西我需要一个新的东西。
答案 0 :(得分:11)
这是我们CS实验室白板上留下的图表。所以你要取一些苹果,然后在开始之前抓住一个延续。你漫步在森林里,收集苹果,最后你在苹果上继续施用。突然间,你在进入森林之前就已经找到了自己的位置,除了你所有的苹果。
(display
(call/cc (lambda (k)
(begin
(call-with-forest
(lambda (f)
(k (collect-apples f))))
(get-eaten-by-a-bear)))))
=> some apples (and you're not eaten by a bear)
我认为可能涉及到成年礼和埋藏的黄金。
答案 1 :(得分:5)
看一下PLAI的延续部分 - 它非常“实用” 面向“,它使用”黑洞“可视化为可以帮助您的延续 理解它。
答案 2 :(得分:0)
学习call / cc没有捷径。阅读The Scheme Programming Language或Teach Yourself Scheme in Fixnum Days中的章节。
答案 3 :(得分:0)
我发现可视化调用堆栈很有帮助。在计算表达式时,请在每个步骤跟踪调用堆栈。 (参见例如http://4.flowsnake.org/archives/602)这可能一开始并不直观,因为在大多数语言中,调用堆栈是隐含的;你不能直接操纵它。
现在将延续视为保存调用堆栈的函数。当调用该函数(值为X)时,它会恢复保存的调用堆栈,然后将X传递给它。
答案 4 :(得分:0)
永远不喜欢call / cc的直观表示,因为我无法将其反映回代码(是的,想象力差);)
无论如何,如果您已熟悉其他语言的例外情况,我认为如果您已经熟悉其他语言的例外情况,那么不要使用call / cc,而是使用call / ec(escape continuation)更容易。
以下是一些应该评估为值的代码:
(lambda (x) (/ 1 x))
如果x等于'0'怎么办?在其他语言中我们可以抛出异常,那么方案呢? 我们也可以扔掉它!
(lambda (x) (call/ec (cont)
(if (= x 0) (cont "Oh noes!") (/ 1 x))))
call / ec(以及call / cc)就像“尝试”一样。在命令式语言中,您可以轻松跳出函数,只返回值或抛出异常。 在功能上你不能跳出来,你应该评价一些东西。并致电/ *来救援。 它的作用是将“call / ec”表示为函数(在我的例子中,这个名称为“cont”),带有一个参数。调用此函数时,它会将WHOLE调用/ *替换为它的参数。
因此,当(cont "Oh noes!")
将(call/ec (cont) (if (= x 0) (cont "Oh noes!") (/ 1 x)))
替换为"Oh noes!"
字符串时。
call / cc和call / ec几乎等于彼此,除了ec更简单的实现。它只允许跳起来,可能会从外面跳下来。