;; A simple CPS transformer which does proper tail-call and does not

;; duplicate contexts for if-expressions.

;;author : Yin Wang(yw21@cs.indiana.edu)

(load "pmatch.scm")

(define cps
  (lambda (exp)
    (letrec
      ([trivial? (lambda (x) (memq x '(zero? add1 sub1)))]
       [id (lambda (v) v)]
       [ctx0 (lambda (v) `(k ,v))] ; tail context
       [fv (let ([n -1])
        (lambda ()
          (set! n (+ 1 n))
          (string->symbol (string-append "v" (number->string n)))))]
      [cps1
        (lambda (exp ctx)
        (pmatch exp
          [,x (guard (not (pair? x))) (ctx x)]
          [(if ,test ,conseq ,alt)
           (cps1 test
            (lambda (t)
              (cond

                [(memq ctx (list ctx0 id))

                `(if ,t ,(cps1 conseq ctx) ,(cps1 alt ctx))]
                [else
                  (let ([u (fv)])
                  `(let ([k (lambda (,u) ,(ctx u))])
                    (if ,t ,(cps1 conseq ctx0) ,(cps1 alt ctx0))))])))]
      [(lambda (,x) ,body)
        (ctx `(lambda (,x k) ,(cps1 body ctx0)))]
      [(,op ,a ,b)
        (cps1 a (lambda (v1)
          (cps1 b (lambda (v2)
             (ctx `(,op ,v1 ,v2))))))]
      [(,rator ,rand)
       (cps1 rator
        (lambda (r)
          (cps1 rand
            (lambda (d)
            (cond
              [(trivial? r) (ctx `(,r ,d))]
              [(eq? ctx ctx0) `(,r ,d k)]     ; ;tail call
                [else
                  (let ([u (fv)])
                    `(,r ,d (lambda (,u) ,(ctx u))))])))))]))])
      (cps1 exp id))))

;;; tests

;; var
(cps 'x)
(cps '(lambda (x) x))
(cps '(lambda (x) (x 1)))

;; no lambda (will generate identity functions to return to the toplevel)
(cps '(if (f x) a b))
(cps '(if x (f a) b))

;; if stand-alone (tail)
(cps '(lambda (x) (if (f x) a b)))

;; if inside if-test (non-tail)
(cps '(lambda (x) (if (if x (f a) b) c d)))

;; both branches are trivial, should do some more optimizations
(cps '(lambda (x) (if (if x (zero? a) b) c d)))

;; if inside if-branch (tail)
(cps '(lambda (x) (if t (if x (f a) b) c)))

;; if inside if-branch, but again inside another if-test (non-tail)
(cps '(lambda (x) (if (if t (if x (f a) b) c) e w)))

;; if as operand (non-tail)
(cps '(lambda (x) (h (if x (f a) b))))

;; if as operator (non-tail)
(cps '(lambda (x) ((if x (f g) h) c)))

;; why we need more than two names
(cps '(((f a) (g b)) ((f c) (g d))))

;; factorial
(define fact-cps
(cps
'(lambda (n)
((lambda (fact)
((fact fact) n))
(lambda (fact)
(lambda (n)
(if (zero? n)
1
(* n ((fact fact) (sub1 n))))))))))

;; print out CPSed function
(pretty-print fact-cps)
;; =>
;; '(lambda (n k)
;; ((lambda (fact k) (fact fact (lambda (v0) (v0 n k))))
;; (lambda (fact k)
;; (k
;; (lambda (n k)
;; (if (zero? n)
;; (k 1)
;; (fact
;; fact
;; (lambda (v1) (v1 (sub1 n) (lambda (v2) (k (* n v2))))))))))
;; k))

((eval fact-cps) 5 (lambda (v) v))
;; => 120

王垠-40行代码 -cps.ss的更多相关文章

  1. 分享一个开源的JavaScript统计图表库,40行代码实现专业统计图表

    提升程序员工作效率的工具/技巧推荐系列 推荐一个功能强大的文件搜索工具SearchMyFiles 介绍一个好用的免费流程图和UML绘制软件-Diagram Designer 介绍Windows任务管理 ...

  2. 王垠的40行代码,究竟diao在哪里

    王垠是谁? 不用我说了吧!!! 别傻谈,亮码瞧! ;; A simple CPS transformer which does proper tail-call and does not;; dupl ...

  3. Python人脸识别最佳教材典范,40行代码搭建人脸识别系统!

    Face Id是一款高端的人脸解锁软件,官方称:"在一百万张脸中识别出你的脸."百度.谷歌.腾讯等各大企业都花费数亿来鞭策人工智能的崛起,而实际的人脸识别技术是否有那么神奇? 绿帽 ...

  4. jquery轮播图详解,40行代码即可简单解决。

    我在两个月以前没有接触过html,css,jquery,javascript.今天我却在这里分享一篇技术贴,可能在技术大牛面前我的文章漏洞百出,也请斧正. 可以看出来,无论是div+css布局还是jq ...

  5. 40行代码爬取猫眼电影TOP100榜所有信息

    主要内容: 一.基础爬虫框架的三大模块 二.完整代码解析及效果展示 1️⃣  基础爬虫框架的三大模块 1.HTML下载器:利用requests模块下载HTML网页. 2.HTML解析器:利用re正则表 ...

  6. 女朋友汇总表格弄了大半天,我实在看不下去了,用40行代码解决问题 | Python使用openpyxl库读写表格Excel(xlsx)

    1.openpyxl基本操作 python程序从excel文件中读数据基本遵循以下步骤: 1.import openpyxl 2.调用openpyxl模块下的load_workbook('你的文件名. ...

  7. 带大家用40行python代码实现一个疫情地图

    最近两个月,因为新冠病毒无情的肆虐,相信会给每个中国人的记忆中画上重重的一笔.到今天为止,疫情形势依然十分严峻,虽然除湖北外的其他省份已经连续十一天确诊人数下降,但是接下来还有将近至少1.6亿的人口迁 ...

  8. 一个只有99行代码的JS流程框架

    张镇圳,腾讯Web前端高级工程师,对内部系统前端建设有多年经验,喜欢钻研捣鼓各种前端组件和框架. 最近一直在想一个问题,如何能让js代码写起来更语义化和更具有可读性. 上周末的时候突发奇想,当代码在运 ...

  9. 王垠:完全用Linux工作

    来自: Zentaur(alles klar) 录一篇旧文 作者:王垠 完全用Linux工作,抛弃windows 我已经半年没有使用 Windows 的方式工作了.Linux 高效的完成了我所有的工作 ...

随机推荐

  1. CG-CTF | MD5

    渣渣今天写了一题misc,第一次学习md5的python写法,赶紧记录一波 背景知识: import hashlib md51=hashlib.md5() md52=hashlib.md5() # [ ...

  2. 170907-关于JavaWeb的题

    1. 答案是B.D Servlet 通过调用 init () 方法进行初始化. Servlet 调用 service() 方法来处理客户端的请求. Servlet 通过调用 destroy() 方法终 ...

  3. es之Source字段和store字段

    PUT /website/blog/ { "title" : "elasticsearchshi是是什么", "author" : &quo ...

  4. iOS-7-Cookbook

    https://github.com/liubin1777/iOS-7-Cookbook 版权声明:本文为博主原创文章,未经博主允许不得转载.

  5. PhantomJs 与 Casperjs

    利用PhantomJS做网页截图经济适用,但其API较少,做其他功能就比较吃力了. CasperJs是对phantomjs的一次封装.即phantomjs是原生的,而casperjs是封装在以phan ...

  6. Gradle 详解

    Gradle简单来说,就是工程的管理,帮我们做了依赖,打包,部署,发布等工作.就像一个管家管理我们的项目,我们只用关心写代码就可以了. 1 gradle-wraaper.properties 主工程的 ...

  7. java valueOf

    valueOf 方法可以将原生数值类型转化为对应的Number类型,java.lang.Number 基类包括ouble.Float.Byte.Short.Integer 以及 Long派生类, 也可 ...

  8. 阶段1 语言基础+高级_1-3-Java语言高级_04-集合_01 Collection集合_4_Iterator接口介绍

    collection集合中是没有索引的,不能使用普通的循环来便利它. 也是在util的包中 先判断集合中有没有元素 有元素就取出来,用next方法 使用接口来接受一个实现类,这就是多态

  9. UI自动化之特殊处理四(获取元素属性\爬取页面源码\常用断言)

    获取元素属性\爬取页面源码\常用断言,最终目的都是为了验证我们实际结果是否等于预期结果 目录 1.获取元素属性 2.爬取页面源码 3.常用断言 1.获取元素属性 获取title:driver.titl ...

  10. Prometheus Alertmanager Grafana 监控警报

    Prometheus Alertmanager Grafana 监控警报 #node-exporter, Linux系统信息采集组件 #prometheus , 抓取.储存监控数据,供查询指标 #al ...