CPS变换的简单理解
来源:互联网 发布:java游戏圈钱 编辑:程序博客网 时间:2024/05/16 00:52
CPS变换又叫做continuation Passing Style,它是一种编程风格,用来将内部要执行的逻辑封装到一个闭包里面,然后再返回给调用者,这就将它的程序流程显式的暴露给了程序员,让我们可以控制它。
我们先看一个cps变换的小例子:
import tracebackdef disp(x): if x>0:disp(x-1) else:print((len(traceback.extract_stack()),x))def test(k,n): #return test(k,n-1) if n>0 else k(42) if n>0: x = test(k,n-1) return x else:return k(42)#注意最后这个(),因为f最后返回一个函数c(42) = def f() :disp(42),所以要调用一下f()C = lambda f: lambda c, *a: f(lambda x: lambda : c(x), *a)()C(test)(disp, 990)#test(disp,990) stack overflow
我们将disp这个函数要做的事情返回给了程序的调用者(caller),这样我们就可以在调用disp这个逻辑的时候,已经从程序的栈里面出来了,这样就可以避免栈的溢出。
上面的代码可以看作我们人肉的改变了disp的运行流程,将这个逻辑封装在一个闭包里面,然后决定什么时候调用。
cps还有其他很多用途,这里我只关注用户代码方面的…一个小例子,如果我们需要实现协程,需要挂起某一个协程,然后需要的时候再执行这个协程。这样我们就需要将要挂起之后执行的逻辑包装起成一个continuation,当需要的时候再执行这个continuation。
[2]continuation对尾递归的优化:这一块感觉有一点难以理解,反正我是看了很久才有一点懂,大概说一下理解吧。首先python,c++这种都是不支持尾递归优化的,所以如果cps变换在这里来讲作用不是很大。但是多了解一点总是好的。对于函数式来说,尾递归就很重要了,因为没有循环可以用。但是有些不好写成尾递归,比如二叉树先序遍历,在函数式里面就很难写成尾递归,这里就要用到continuation。而continuation则可以将本来在栈里面的调用被我们强行赛入一大堆lambda函数里面(利用闭包捕获调用的上下文)
具体怎么理解呢,首先continuation看作是接下来要做的工作,传入的continuation则代表上面的调用者希望继续完成的工作,利用当前的一层包装将当前的工作塞入新的continuation里面就完成了继续要做的工作的抽象!然后传入下一个参数里面,我们看一个fib数列的理解,首先当前的上面传入一个continuation是要做的工作,我们自己要做的是求出fib(n-1)和fib(n-2)并且将这两个加起来。关键是怎么抽象成下一个continuation?这里我想了特别久,最后是这么理解的:
先考虑直接调用fib_cps(n-1,”new continuation”),这个框架是肯定的。然后考虑下一次调用直接到递归出口了,那么肯定就要调用continuation(n),这样就开始展开计算了。这个n传入的参数不就是调用者的continuation接受的参数吗?所以continuation可以确定这样一部分:lambda x: continuation….,然后我们接下来还要计算fib(n-2),这一部分怎么搞呢?可以这样写:fib_cps(n-2,lambda y:continuation(x+y)),这样组合起来就成了下面的代码.注意理解,y是fib_cps(n-2)的返回结果,我们将最终的展开结果相加这个工作放到了新的里面的continuation上面去做。展开到这一层x+y算是完成这个递归调用的工作了,剩下的展开就需要后面的展开了。
def fib_cps(n,k): if n<2:return k(n) #x是fib_cps(n-1)的返回结果,y是fib(n-2),是第二个continuation返回的结果 return fib_cps(n-1,lambda x:fib_cps(n-2,lambda y:k(x+y)))def _k(x):return xx = fib_cps(10,_k)print(x)
0 0
- CPS变换的简单理解
- 理解 JavaScript 标准的回调模式( CPS )
- 离散傅立叶变换 - 简单理解
- 简单理解霍夫变换
- 距离变换的理解
- Hough变换的理解
- 傅立叶变换的理解
- Hough变换的理解
- D3D变换的理解
- 通过 Fibbonacci 理解 CPS;通过 CPS 理解 Fibbonacci
- CPS的概念
- 一个简单的变换
- 傅立叶变换的深入理解
- 傅立叶变换的深入理解
- OpenGL变换顺序的理解
- 小波变换的理解
- AS3 的简单变换效果
- 阿达马变换的简单介绍
- Max中四边面转三角面的方法
- 2016/11/20
- hdu1018 Big Number
- vfork小实例
- 移动IM开发那些事:技术选型和常见问题
- CPS变换的简单理解
- java实现银行家算法
- JVM类加载机制
- Windows程序编程(3):事件、菜单、控件
- SpringMVC加载配置Properties文件的几种方式
- 静态代理模式浅析
- iOS:Objective-C笔记
- 个人阶段总结框架及深度学习简单理解
- study-5系统优化