有人能用简单的话解释一下 call/cc 吗?

2024-04-05

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


并非所有实现call/cc完全相同,但希望这个答案可以适用于所有常见的变体,包括球拍,没有什么麻烦。这个故事其实是根据c内置于Unlambda http://www.madore.org/~david/programs/unlambda/#callcc.

呼叫/抄送的隐喻

你是一位超级英雄考古学家,正在挖掘古老的玛雅遗址。您会在优雅的拱门中发现一处构造精美、保存完好的石门。但这只是一个门,是侧着的;它附近没有任何一堵墙,它似乎也不是墙的一部分。您的工作人员可以读取它的能量读数,因此您可以将其完好无损地运回实验室进行研究。

在您的实验室中,一个大钟挂在现在直立的拱门正前方的墙上,您将其放置在房间中央附近。在检查拱门时,您会穿过它。

4:17 PM

穿过拱门后,您会惊奇地发现,您手里拿着一个立方体盒子,它大到足以在里面放一本书,有一个盖子和一个发光按钮。你不记得拿起过这样一个盒子,也不记得以前见过它。你叫来你的助手,询问盒子是从哪里来的。助手不知道。如果您放下盒子,按钮就会停止发光。你再次拿起它,按钮再次发光。只有当你握住它时它才会发光;如果助手拿起盒子,它就不会发光。在百灵鸟中,您将一个回形针放入盒子中,合上盖子,然后按下按钮。

4:23 PM

穿过拱门后,您惊讶地发现您手里拿着一个回形针。你不记得捡起过它。你的助手在房间里,目瞪口呆地看着你。你不记得你的助手走进过房间。您的时钟似乎也快了几分钟。

“刚刚发生了什么?”助手问道。

“我刚刚走过拱门,”你说,并没有真正理解这个问题。

“不,你没有!那盒子怎么了?”助手说。

“你在说什么?”你说,越来越生气了。

...

一旦整个情况发生,并且您了解了这个拱门的作用,您决定做一些大胆的事情。您大声读出当前时间,然后穿过拱门。

5:30 PM

从拱门出来,你手里拿着一个空盒子。观察到时间如您所料,为下午 5:30,您将一张便利贴贴在标有“#1。你把盒子放在桌子上,大声读出当前时间,然后再次穿过拱门。

5:31 PM

从拱门出来,你手里拿着一个空盒子。观察到时间如您所料,为下午 5:31,您将一张便利贴贴在标有“#2 - use to forget。你放置框 #2inside盒子#1(当你这样做时,它会缩小到其大小的一小部分;看起来这些盒子就是为此而设计的)。

Being a 超级英雄考古学家,然后你适当地装备自己,闯入你最不喜欢的压迫政权的外国大使馆,突破它的金库并窃取一些严格保守的国家机密的纸质副本。香港动作片里的东西,子弹和拳头飞舞。你把自己关在金库里,在他们的守卫找到你之前争取宝贵的时间。从你的包里拿出1号盒子,把文件塞进去(和2号盒子一起,但不是里面),关闭1号盒子,就在金库门被吹开的时候,你微笑着,拉了拉扣住别针,放下手榴弹,然后按下按钮。

9:45 PM

从拱门出来,你拿着一个空盒子,上面贴着标签#2 - use to forget以及包含您最不喜欢的压迫政权的敏感国家机密的文件。您还注意到时间不是您预期的下午 5:30,而是晚上 9:45,因此您没有继续执行预期的闯入计划。你坐下来,把文件的内容记下来,一旦你确定你已经完全记住了它们,你就把文件烧进垃圾桶。现在,您大声读出当前时间并穿过拱门。

2:00 AM

从拱门出来,你手里拿着一个空盒子。观察到当前时间如您所料,为凌晨 2:00,您立即为新盒子添加标签#3 - use to remember。你给自己写了一张简短的便条:Allow self to forget again. At exactly 7:15 PM call police and report suspicious persons at 14th and Maple.将框 #3 和注释放在框 #2 内,然后单击框 #2 上的按钮。

2:01 AM

从拱门出来,你拿着一个空盒子,上面贴着标签#3 - use to remember,以及您亲笔写的注释。时间比预计的下午 5:31 晚很多,因此您没有继续执行预定的闯入计划。按照你给自己的指示,你再次穿过拱门,获得一个你贴上标签的新盒子#4 - use to forget。你按照笔记中的指示打电话给警察,但不知道为什么,几天后你在新闻中听到一个国际间谍团伙在你的家乡被捣毁。

任务完成! (你假设。)从这一点开始,你可以选择了解信息本身,但不知道你用它做了什么;或者不知道该信息,但知道它是如何使用的。

最后,这个美妙的工具是有代价的。当你在各种活动中继续依赖拱门时,你必须知道你将永远分裂你的生活,并且除非通过在你的许多替代自我之间发送消息,否则这些碎片永远无法统一。按钮盒的一次使用可能会导致许多珍贵记忆的不可挽回的损失,这可能是一种策略,也可能是一个严重和悲剧性的错误。

解释

穿过拱门代表着call/cc手术。这样做会创建一个新的按钮框,它代表一个延续函数。将东西放入框中表示将参数传递给延续函数。按下方框上的按钮代表调用延续函数。

按下盒子上的按钮(调用延续函数)会使故事字符(带有变量的调用堆栈)恢复到创建盒子(延续)时的确切状态,即创建该盒子时的状态。call/cc最初完成。传递给延续的参数成为原始的结果值call/cc堆栈恢复后;这就是为什么按下按钮后,故事中的角色拿着的不是盒子,而是盒子里的东西。

盒子(延续)可以被封装(互相传递),允许使用call/cc作为实现协同例程、状态机和其他高级构造的原语。

延续还可以用来以不方便的方式轻松逃离代码分支(“扔下手榴弹,按下按钮”),例如立即退出深层嵌套的条件和导致副作用的循环。

另请注意,拱门不是时间机器;它是一个时间机器。时间在故事中永远不会逆转,故事人物走过拱门的外部事物也不会逆转。 (破坏性赋值、对堆内存的更改以及其他副作用不会通过调用延续函数来逆转。)

练习:为要遵循的故事人物编写伪代码,这将导致正确执行所描述的间谍计划。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

有人能用简单的话解释一下 call/cc 吗? 的相关文章

  • Racket 中的反向列表,时间复杂度为 O(n)

    我需要在Scheme中编写一个递归函数 它接受一个原子列表并在线性时间内反转它 我只能使用define lambda cons car cdr cond let 和null 这是我到目前为止所拥有的 define reverse lambd
  • 在这种情况下如何在 Racket 上订购我的累积变量?

    出于教育原因 我使用 Racket 进行编码 我收到了一项任务 其中我应该创建一个函数 在没有过滤器的情况下 它将接收一个列表作为输入 并仅返回另一个列表 其中包含第一个列表的偶数 我提出了迭代过程的递归定义 define add even
  • struct 是 Racket 中的宏吗?

    我记得我在某处读到它不是宏 而是内置于核心语言中的 类似的事情 我不确定 因为我已经记不起我是从哪里读到的了 也是如此structRacket 中是否有宏 如果不是 为什么它被内置到核心语言中 一个宏 struct rkthas defin
  • 为什么(begin)在Scheme中有效?

    我在 Racket 和 Chez Scheme 中进行了测试 发现 begin 是可以接受的 同时 define a begin 不是 例如我得到的球拍 gt begin gt define a begin stdin 56 10 begi
  • 如何根据 Racket Web servlet 中的路径显示不同的内容?

    我正在尝试遵循有关简单网络应用程序的 Racket 指南上的教程 但无法得到一个基本的东西 如何让 servlet 根据请求 URL 提供不同的内容 尽管我进行了搜索 但即使是巨大的博客示例也是一个大文件 并且所有内容都在我背后用巨大的 g
  • 在球拍中使用 stop-when

    我一直在搞这个程序 它需要一个数字并加 1 我想知道你到底如何使用stop when这里 例如 让它停在 5 点 我想这里需要一个 cond 声明 谢谢 require 2htdp image require 2htdp universe
  • 我的代码发出错误“应用程序:不是过程”或“调用非过程”

    在执行我的代码期间 我在不同的方案实现中遇到以下错误 Racket application not a procedure expected a procedure that can be applied to arguments give
  • 尾递归Map函数RACKET

    Racket 中的映射函数采用一个函数和一个列表 并将该函数递归地应用于列表中的每个项目 我正在尝试将映射转换为尾递归函数 这该如何完成 你被困在哪里了 您可以定义自己的map程序与内部loop程序 define map f in defi
  • 对于方案中的每个和地图

    这两个功能在方案上有什么区别吗 我正在使用 Dr Racket R5RS 语言制作一个模拟器游戏 我无法决定哪个更好 for each从左到右计算列表元素上的给定函数 并丢弃函数的返回值 它非常适合对列表中的每个元素进行副作用操作 map以
  • 方案相当于元组拆包是什么?

    在Python中 我可以做这样的事情 t 1 2 a b t a 将是 1 b 将是 2 假设我有一个列表 1 2 在方案中 有什么办法可以做类似的事情let 如果有什么区别的话 我会使用 Racket 在球拍中你可以使用match htt
  • 球拍累加器列表功能

    我正在研究创建您可能玩过的 2048 游戏的具体步骤 它位于许多在线网站上 基本上这个函数所做的就是 1 所有空格移到后面 2 如果前两个数字相等 则加倍并检查每两个数字 这些是我所坚持的步骤的说明 设计一个向左滑动的函数 使其运行sing
  • eq 之间的区别?和 = 在方案中?

    gt eq 1 1 t gt eq 1 1 1 1 f gt 1 1 1 1 t 这是DrScheme 中的交互窗口 有人可以解释一下 和 eq 之间的区别吗 在计划中 比较数字 等式 测试参数是否表示内存中的同一数据对象 当量 应该在第二
  • 在 Racket 源代码中选择学生语言

    我正在尝试为 DrRacket 编写一个源文件 指定其中一种语言如何设计教学语言的程序 see 球拍文档 http docs racket lang org drracket htdp langs html 我知道我可以在 DrRacket
  • 在Scheme中编写一个自动记忆器。有关宏和包装器的帮助

    我在Scheme中编写自动记忆器时遇到了一些问题 我有一个有效的 memoize 函数 它创建一个哈希表并检查该值是否已经计算出来 如果之前已经计算过 则返回值 否则调用该函数 define memoizer fun let a table
  • 将自然数转换为特定基数并将其作为列表返回

    我想将函数的结果显示为列表而不是数字 我的结果是 define lst list define num gt base n b if zero n append lst list 0 append lst list 10 num gt ba
  • 什么是“3D语法”?

    在编写 Racket 宏的上下文中 3D 语法 是什么意思 这句话我听过好几次了 包含一次对宏的引用I正在写作 但那是不久前的事了 我修复了它 现在我不记得我最初做错了什么 另外 是 3D 语法吗always坏的 或者是像eval 如果你认
  • Scheme 和 Racket 中嵌套引号的行为

    在 Racket 中编写函数时 我不小心在符号前面放了两个单引号而不是一个 即我不小心写了 a 并发现嵌套引号的一些行为看起来很奇怪 我正在使用 DrRacket 并使用 Racket lang 和 R5RS lang 对此进行了测试 wr
  • 使用map或reduce或filter,在Scheme中,计算列表中有多少个元素[关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 number length 1 1 0 1 0 0 这假设返回 6 我知道如何使用长度并找到它 但我不知道如何在没有长度的情况下使用映射或过
  • 球拍博士中的位图[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 如何在 drracket 中的框架 gui 上加载位图 请给出必要的代码和参考文献 我承认 我很难在文档中找到正确的位置来指向您 这是
  • 在Racket中将结构递归转化为累积递归

    我有一些代码来查找最大高度并将其替换为关联的名称 身高和姓名有单独的列表 每个列表的长度相同且非空 我可以使用结构递归来解决这个问题 但必须将其更改为累积递归 而且我不确定如何做到这一点 我见过的所有例子都让我困惑 有人能够将代码变成使用累

随机推荐