SICP习题1.6深入分析
来源:互联网 发布:淘宝军品店 编辑:程序博客网 时间:2024/05/16 13:46
new-if在用在递归函数时,会导致栈溢出,这是很多资料里提到的,对于资质愚鲁的我,这个结果还是略显跳跃了点,于是苦思了几天,分析如下:
先给出定义代码:
(define (new-if predicate if-clause then-clause) (cond (predicate if-clause) (else then-clause) ))(define (TailSum num) (new-if (= 0 num) 0 (+ num (TailSum (- num 1)))) )
上面的递归函数TailSum其实就是求1到n的累加,为什么会堆栈溢出呢,假如调用形式是这样的:
(tailsum 1)
那么解释器会这样执行:
1、判断tailsum不是special form,求值所有入参,这里只有“1”
2、入参求值完毕,展开tailsum
3、展开后变成(new-if (= 0 1) 0 (+ 1 (TailSum (- 1 1))))
4、判断new-if不是special form,求值所有入参
4.1、求值入参(= 0 1)求值为#f
4.2、求值入参0求值为0
4.3、求值入参(+ 1 (TailSum (- 1 1))
4.3.1、判断+为special form,求值所有入参
4.3.2、求值入参1为1
4.3.3、求值入参(TailSum (- 1 1))
4.3.3.1、判断tailsum不是special form,求值所有入参
4.3.3.2、求值入参(- 1 1)为0
4.3.3.3、再次展开(tailsum 0)中的函数tailsum
4.3.3.3.1、展开后变成(new-if (= 0 0) 0 (+ 0 (TailSum (- 0 1))))
4.3.3.3.2、判断new-if不是special form,求值所有入参
4.3.3.3.3、求值入参(= 0 0)求值为#t
4.3.3.3.4、求值入参0求值为0
4.3.3.3.5、求值入参(+ 1 (TailSum (- 0 1))
4.3.3.3.5.1、判断+为special form,求值所有入参
4.3.3.3.5.2、求值入参0为0
4.3.3.3.5.3、求值入参(TailSum (- 0 1))
4.3.3.3.5.3.1、判断tailsum不是special form,求值所有入参
4.3.3.3.5.3.2、求值入参(- 0 1)为-1
4.3.3.3.5.3.3、再次展开(tailsum -1)中的函数tailsum
.....................................
可以看出,因为new-if不是special form,所以不像真正的if那样,在求出predicted后,只执行最后入参的其中一个,最终会只执行then-clause,然后返回
而new-if会被解释器当做用户定义的普通函数,根据“应用序”的求值规则,解释器会先把所有入参求值,然后才会调用用户定义的函数,然后其中一个入参恰好就是用户定义的函数,所以入参求值会永远进行下去,上面的调用即使是(tailsum 0),仍然会因为对入参的无限求值而最终耗尽堆栈
那么,如果解释器是正则序求值的,是不是就不会溢出了,答案是:是的
同样拿上面的例子来单步:
1、判断tailsum不是special form,先展开用户函数
2、展开后变成(new-if (= 0 1) 0 (+ 1 (TailSum (- 1 1))))
2.1、判断new-if不是special form,继续展开用户函数
2.2、展开后变成(cond ((= 0 1) 0) (else (+ 1 (TailSum (- 1 1))))
2.3、判断cond是special form,但predicate为#f,跳到cond的else分支
2.3.1、判断(TailSum 0)不是special form,展开
2.3.2、展开为(new-if (= 0 0) 0 (+ 0 (TailSum (- 0 1))))
2.3.2.1、判断new-if不是special form,展开new-if
2.3.2.2、展开后变成(cond ((= 0 0) 0) (else (+ 1 (TailSum (- 0 1))))
2.3.2.3、判断cond为special form,且predicate为#t,返回0
2.3.3、(new-if)返回0
2.3.4、(tailsum 0)返回0
2.4、cond返回else的+1为1
3、(tailsum 1)返回1
总结:
应用序是先求值入参,再展开函数
正则序是先展开函数,再求值入参
前者有求值顺序的问题,但节约栈空间;后者没有求值顺序的问题,但很费栈空间,且有冗余计算的情况
- SICP习题1.6深入分析
- SICP习题1.6的解答
- SICP习题
- sicp 第一章习题试做
- sicp 第一章 习题
- sicp 2.2 习题
- sicp 2.3-2.5 习题
- SICP 部分习题答案
- SICP 习题答案1.1
- SICP 习题答案1.2
- SICP 习题答案1.3
- SICP 习题答案1.4
- SICP 习题答案1.5
- SICP 习题答案1.11
- sicp习题2.1
- sicp习题2.2
- sicp 习题2.3
- sicp 习题2.5
- 工作小结----转眼2年了,该给自己总结一下了
- 查看 Oracle 是32位还是64位的方法
- 数据结构
- 我看盛大 [以下内容仅为个人观点]
- invalidate和状态栏的SetText函数发生死锁了!
- SICP习题1.6深入分析
- VS在Release下设置断点调试信息
- 游园
- 经典电影收藏
- 让xp系统在开启和关闭时显示加载信息
- 什么是内部类?Static Nested Class 和 Inner Class的不同
- 在Aptana Studio 2 中使用JSLint
- 2012百度招聘笔试题目
- JSP使用ckfinder实现中文图片上传后,无法显示,主要是tomcat不支持中文路径