;; 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. Presenter 层

    后是 Presenter 层,它是处理业务逻辑和业务数据的,所以必须持有 Model 的引用,同时要将处理完的数据交给 View 层用于显示,也必须持有 View 的引用,那么,一开始我们就要把这两层 ...

  2. glm初试,关于行矩阵列矩阵问题

    /*** * glm中矩阵是行优先存储的,这不同于opengl默认的以列优先存储的方式??,以下面矩阵mat为例 * 它是用四个行向量来模拟存储四个行:vec4 value[4],其中 * value ...

  3. element-ui的rules全局验证

    原文:https://www.jianshu.com/p/6a29e9e51b61 rules.js var QQV = (rule, value, callback) => { debugge ...

  4. 解决ubuntu18.04使用vi编辑器方向键错乱

    1.编辑 vimrc.tiny 文件 vi /etc/vim/vimrc.tiny 2.修改下述内容 修改 set compatible 为 set nocompatible 添加 set backs ...

  5. python-笔记(六)模块操作以及常用模块简介

    模块.包 什么是模块? 模块实质上就是一个python文件,它是用来组织代码的,意思是说把python代码写到里面,文件名就是模块的名称,例如:model.py model就是模块名称. 什么是包? ...

  6. 博客图片上传picgo工具安装配置github图传使用

    摘要 对于每一个写博客的人来说,图片是至关重要.这一路经历了多次图片的烦恼,之前选择了微博个人文章那里粘贴图片的方式上传,感觉也挺方便的.但是由于新浪的图片显示问题,如果header中不设置 标签就不 ...

  7. Python解决NameError: name 'reload' is not defined的问题

    遇到这个问题,对于 Python 2.X: import sys reload(sys) sys.setdefaultencoding("utf-8") 对于 Python 3.3 ...

  8. 【ABAP系列】SAP MB5B中FI凭证摘要是激活的/结果可能不正确 的错误

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[ABAP系列]SAP MB5B中FI凭证摘要是 ...

  9. Java之九九乘法表

    public class MultiplicationTable { public static void main(String[] args) { for(int i=1;i<=9;i++) ...

  10. hdu-4185.loiol_skimming(简单二分匹配模型)

    /************************************************************************* > File Name: hdu-4185. ...