call/cc分析一例

(define (fact n)
  (let ((r 1) (k ‘void))
    (call/cc (lambda (c) (set! k c)))
    (set! r (* r n))
    (set! n (- n 1))
    (if (= n 1) r (k ‘recurse))))

(fact 5)

老师:为什么能工作?
学生:不知道!
老师:(call/cc (lambda (c) (set! k c))) 干了什么?
学生:call/cc 的全称是 call-with-current-continuation, 它调用一个单参数的函数,调用时把当前延续作为那个单参数函数的参数。 所以,上式就是把当前延续存入 k 中。
老师:当前延续是什么?
学生:(escaper (lambda (~) (~ (set! r (* r n)) (set! n (- n 1)) (if (= n 1) r (k ‘recurse)))))
老师:怎么存入 k ?
学生:(set! k (escaper (lambda (~) (~ (set! (* r n)) (set! n (- n 1)) (if (= n 1) r (k ‘recurse))))))
老师:(call/cc (lambda (c) (set! k c))) 和 (set! k (escaper (lambda (~) (~ (set! (* r n)) (set! n (- n 1)) (if (= n 1) r (k ‘recurse)))))) 等价吗,可以相互替换吗?
学生:可以!

(define (fact n)
  (let ((r 1) (k ‘void))
    (set! k
          (escaper (lambda (~) (~ (set! (* r n)) (set! n (- n 1)) (if (= n 1) r (k ‘recurse)))))) ;; A
    (set! r (* r n)) (set! n (- n 1)) (if (= n 1) r (k ‘recurse))))                               ;; B

老师:为什么能工作?
学生:跟踪一下 (fact 5) 就知道了

B: n=5 => r=5,  n=4  [ n != 1,continue ]
A: n=4 => r=20, n=3  [ n != 1, continue ]
A: n=3 => r=60, n=2  [ n != 1, continue ]
A: n=2 => r=60, n=1  [ n == 1, return r and escape ]

老师:为什么是递归的?
学生:因为延续是一种函数,延续递归了,这个延续函数就递归了。

老师:这里的延续本质上还是递归。尽管延续被叫做有上下文的 goto,这个程序也可以看成用了 goto 的。

(define (fact n)
  (let ((r 1) (k ‘void))
    (call/cc (lambda (c) (set! k c)))
    (set! r (* r n))
    (set! n (- n 1))
    (if (= n 1)
        r
        (k ‘recurse) ;; => go back to (call/cc (lambda (c) (set! k c)))
        )))

学生:但这只是一种“比喻”,实质上它是递归!
老师:你说的对。
时间: 2024-10-14 05:15:32

call/cc分析一例的相关文章

以慕课网日志分析为例 进入大数据 Spark SQL 的世界

详情请交流  QQ  709639943 01.以慕课网日志分析为例 进入大数据 Spark SQL 的世界 02.漫谈spring cloud分布式服务架构 03.Spring Cloud微服务实战视频课程 04.漫谈spring cloud 与 spring boot 基础架构 05.Java秒杀系统方案优化 高性能高并发实战 06.Java深入微服务原理改造房产销售平台 07.快速上手Linux 玩转典型应用 08.快速上手Ionic3 多平台开发企业级问答社区 09.Java Sprin

CK2255-以慕课网日志分析为例 进入大数据 Spark SQL 的世界

新年伊始,学习要趁早,点滴记录,学习就是进步! 随笔背景:在很多时候,很多入门不久的朋友都会问我:我是从其他语言转到程序开发的,有没有一些基础性的资料给我们学习学习呢,你的框架感觉一下太大了,希望有个循序渐进的教程或者视频来学习就好了.对于学习有困难不知道如何提升自己可以加扣:1225462853  获取资料. 下载地址:https://pan.baidu.com/s/1hsU5EIS 以慕课网日志分析为例 进入大数据 Spark SQL 的世界 本课程以"慕课网日志分析"这一大数据应

DB buffer bussy wait 分析一例

DB层分析OI DB层分析OI的信息如下: 1. 异常时间段,  Logical reads:/ Physical reads/ Physical write  指标都低于正常时间段.说明数据库本身消耗i/o 并不高.但是nmon显示disk 读写非常高, 同时现场分析, I/O 资源消耗最大可达40M-70M/s,任务可以顺利完成.同时注意到 通过topas 来看,在一些时候,hdisk 在 tps和kbps 为0的情况下,磁盘繁忙程度达到99%,所以建议如下: 是这个现在已有的信息能够看到的

线上LVS负载均衡请求不转发案例简单解决分析一例

线上某架构组织结构基本如下: 基本架构描述: 前端采用的是lvs+keepalived做负载均衡和高可用,用来转发客户的请求给后端的业务服务器,也就是那4组nginx+tomcat业务服务器.说的更直白一些,那几台nginx+tomcat可以简答理解为lvs的客户端. 故障描述: 其中lvs转发到58.2.12.20这台服务器的时候, ActiveConn的值还有一些,InActConn几乎是没有数值的.为了这个问题纠结了好几天迟迟未能解决,由于刚到公司也不能不解决这些问题哦. 解决思路: 1)

音乐app的分析(例:QQ音乐)

<一>QQ?乐最核心的功能就是歌曲的播放. 播放音频,首先想到可以用AVFoundation框架,来完成播放音乐的主要功能.但是AVFoundation只能播放本地的音乐,不能在线播放.虽然可以先从网络下载资源到本地再播放,但是必须要整首歌都下载完成后才能播放,这样效果并不好. ! 如果想在线播放,可以选择AudioToolbox框架中的音频队列服务Audio Queue Services.音频队列服务可以完成音频的录制和播放. 一个?频服务队列Audio Queue有三部分组成: 三个缓冲器

采用[ICONIX] 方法实践分析和设计之二 [用例建模](转)

在上一篇文章中我们了解并进行了域建模,换言之我们有了一个好的开始,起码开发人员对自己要开发的软件已有了初步的认识,且也得到了进行交流时可以使用的术语表. 本章将会在前一篇的基本上进一步阐述使用ICONIX方法实践用例建模,同样在文章的最后还会有在这个阶段最容易犯的10个错误,以给大家提醒或在分析过程中进行参照.     本文在ICONIX方法中所处的位置如下图(红圈标记的地方)     在开始进行用例建模之前,我们需要对这一过程有一些粗线条的认识,如果您以前做过或学习过这方面的知识,可以把下面的

需求用例分析之二:级别设置

在<编写有效用例>(阿莱斯特-科伯恩著,下面用科伯恩用例来指代)一书中,赋予了用例不同的级别,科伯恩形象的设定了例如以下级别:海平面.云朵.风筝.蛤等等. 科伯恩建议用例级别分为多个个目标层次:概要.用户目标.子功能,书写需求用例时,仅仅能选择其一,以下对其详细说明: 概要:包含多个用户目标,它有"显示相关目标的生命周期顺序"和"为低层用例提供一个文件夹表"的功能,概要用例通常须要运行几个小时.几天.几个星期.几个月.甚至几年. 用户目标:它是主运行者努

VCL源码分析方法论(以TButton.Caption属性的由来为例)

最近一段时间似乎流行源码分析:)我也来谈谈在过去一段时间里对VCL源码的分析方法方面的一点体会,本文将不探讨VCL类库的构架和设计模式方面的东本,只是以我们常见的控件属性/方法的实现过程作简单的说明,希望对初学者有所帮助. VCL分析方法例:TButton.Caption属性的由来(本文仅以此献给DELPHI初学者)用过一段时间DELPHI的朋友,都会对VCL源码感兴趣.本人也常常在各大论坛见到一些网友研究讨论过关于VCL源码的贴子.不过,很多网友很努力的想看懂,可最后还是半途而废,因为他们总是

需求用例分析之级别设置

在<编写有效用例>(阿莱斯特-科伯恩著,以下用科伯恩用例来指代)一书中,赋予了用例不同的级别,科伯恩形象的设定了如下级别:海平面.云朵.风筝.蛤等等. 科伯恩建议用例级别分为多个个目标层次:概要.用户目标.子功能,书写需求用例时,只能选择其一,下面对其具体说明: 概要:包括多个用户目标,它有"显示相关目标的生命周期顺序"和"为低层用例提供一个目录表"的功能,概要用例通常需要执行几个小时.几天.几个星期.几个月.甚至几年. 用户目标:它是主执行者努力使工作