SICP学习笔记(1.1.7 ~ 1.1.8)
SICP学习笔记(1.1.7 ~ 1.1.8)
周银辉
1, 牛顿法求平方根
1.1.7节基本上时在逐步引入"递归"的概念, 很简单, 关于各种递归的概念将放在1.2中介绍, 如果对牛顿法(Newton Method)感兴趣可以参考这里:http://en.wikipedia.org/wiki/Newton%27s_method
2, 练习1.6
对于为模仿 if 而定义的 new-if :
(define (new-if predicate then-clause else-clause)
(cond (predicate then-clause)
(else else-clause)))
在使用它来求平方根时会有什么问题
(define (sqrt-iter guess x)
(new-if (good-enough? guess x)
guess
(sqrt-iter (improve guess x)
x)))
答案是, 使用new-if时sqrt-iter会无限次递归
这个题有点杀脑细胞, 原因在于我们思考这个问题的时候采用的是"正则序", 而Scheme解释器在思考这个问题的时候采用的是"应用序".
(事实上, 按照我的大脑的常规思维方式, 会先采用正则序,即那个new-if展开到其定义是采用的cond语句中, 然后再采用应用序, 将good-enough进行求值...然后... 哇, 多么混乱的思维啊,正则序和应用序交叉着用, 所以一开始很难想明白上述代码究竟出了什么问题)
另外一个干扰思维的东西, 是我们根深蒂固的if (或cond ,switch 等) 思想, 我们一直认为"不满足条件的分支语句等不到执行". 这句话其实并不完全正确,这取决于具体的语言,具体的编译器或解释器.
假设有这样的语句, if ( a ) b; else c; 我们可以这样理解: 如果a成立, 那么执行语句b, 否则执行语句c, 这是常规的理解方式. 我们也可以这样理解: 如果a成立, 那么将过程b的返回值作为整个过程的返回值, 否则将过程c的返回值作为整个过程的返回值. 而对于后一种理解方式又会引出另外一个问题:过程b和过程c是在什么时候被求值的? 如果它们是在判断了if(a)是否成立之后求值,那么其又演变回第一种思维方式,其实质是"正则序"求值, 如果它们是在判断if(a)是否成立之前被求值的, 那么b c 始终都会被求值,无论a是否成立, 它们的求值结果作为if...else 过程的参数参与 if...else 运算. 此时, 实质是"应用序"求值.
对于scheme中 if (包括cond) 采用的是正则序还是应用序,我不好说, 但至少可以说, if 是特殊形式, 不是普通过程, 所以其不会单纯地使用应用序, 所以我们可以看到"不满足条件的分支语句等不到执行". 而上面的new-if是一个普通过程, 所以其是应用序的.
为了验证上面的论证, 编写如下程序:
我们会得到如下结果:
"Yes"
"Yes"
yes
yes no
很明显, 无论判断条件是否成立 new-if中两条分支都得到了执行, 只不过, 只有那个条件成立的分支的求值结果将作为整个过程的最后结果.
回到上面求平方根的问题, 在使用new-if时 ,整个表达式将采用应用序, sqrt-iter将被先求值后代入到cond中, 而在进行sqrt-iter求值时其是递归调用, 并且无法执行到cond语句进行返回, 所以递归将无穷地进行下去.
3, 练习 1.7
在检测good-enough?时使用“变化率”而不是使用绝对数值。
这明显是可行的,并且比使用绝对数值更加科学。使用绝对数值时存在的问题是,如果结果值太大或太小,则无法达到所需的精度或与精度之间的误差太大。
4, 自由变量 和 约束变量
对于自由变量(free variable)和约束变量(bound variable,或称 虚变量 dummy variable),在"形式语言"中有着比较严格的定义,可以参考这里,或翻阅一下大学教材。但理解起来似乎都有些头晕目眩的,如何比较“感性”地判断一个变量时自由的还是被约束的呢(“感性”在很多时候意味着“快速地”,同时也意味着是”没有经过论证的”)?
比如下面的函数:
![](https://images.cnblogs.com/cnblogs_com/zhouyinhui/Sum1.PNG)
我们说变量 x 是约束变量, 而 a 是自由变量。
可以通过这样的变量来判断一个变量时自由还是约束的:
(1)自由变量可以替换成一个简单的值(比如数值或对象),而整个函数的还是又意义的,而约束变量则不可以。比如将上面的 a 替换成 3 ,仍是一个完整的求和运算,但如果将 x 替换成 3, 则 3=1 就讲不通了,整个函数表达式失去了原有的意义甚至是错误的。
(2) 自由变量可以提取到函数外部来,而约束变量被约束在函数内部,比如将上述函数表达式中的 a 提取出来,变成:
![](https://images.cnblogs.com/cnblogs_com/zhouyinhui/Sum3.PNG)
仍是可以的,但,我们却不可以将 x 提取出来。
另外,约束变量之所以用“约束”一词,是因为其的确被其”上下文(Context)“所约束了,这个约束很可能就是函数所要表达的逻辑意义或数学含义。我无法明确告诉你这里面有什么规则或定义,但是,比如上面的求和运算,x 被“From 1 to 10" 这样的上下文给约束了. 又比如:
其中 x 是约束的,y是自由的
5, 作用域
关于作用域(Scope)的基本概念和基于具体语言的判定方法就不谈了,不过值得了解的是作用域的两种基本类型:静态作用域(Static Scoping) 和 动态作用域(Dynamic Scoping)。
静态作用域, 我们现在大部分语言(C/C++ C# Java等等)都是使用的这种方式,其名字和对象的绑定发生在编译时,也就是说通过词法分析语法分析等变可以确定,而不需要等到运行时。而在动态作用域里,编译器无法确定名字和对象的绑定,必须等到运行时。
具体的,如何确定这些作用域,推荐看看《程序设计语言——实践之路 》的3.3.1和3.3.2,其讲得非常详细(这里有试读版本:http://book.csdn.net/bookfiles/109/1001098099.shtml)。
注:这是一篇读书笔记,所以其中的内容仅属个人理解而不代表SICP的观点,并随着理解的深入其中的内容可能会被修改
周银辉
1, 牛顿法求平方根
1.1.7节基本上时在逐步引入"递归"的概念, 很简单, 关于各种递归的概念将放在1.2中介绍, 如果对牛顿法(Newton Method)感兴趣可以参考这里:http://en.wikipedia.org/wiki/Newton%27s_method
2, 练习1.6
对于为模仿 if 而定义的 new-if :
(define (new-if predicate then-clause else-clause)
(cond (predicate then-clause)
(else else-clause)))
在使用它来求平方根时会有什么问题
(define (sqrt-iter guess x)
(new-if (good-enough? guess x)
guess
(sqrt-iter (improve guess x)
x)))
答案是, 使用new-if时sqrt-iter会无限次递归
这个题有点杀脑细胞, 原因在于我们思考这个问题的时候采用的是"正则序", 而Scheme解释器在思考这个问题的时候采用的是"应用序".
(事实上, 按照我的大脑的常规思维方式, 会先采用正则序,即那个new-if展开到其定义是采用的cond语句中, 然后再采用应用序, 将good-enough进行求值...然后... 哇, 多么混乱的思维啊,正则序和应用序交叉着用, 所以一开始很难想明白上述代码究竟出了什么问题)
另外一个干扰思维的东西, 是我们根深蒂固的if (或cond ,switch 等) 思想, 我们一直认为"不满足条件的分支语句等不到执行". 这句话其实并不完全正确,这取决于具体的语言,具体的编译器或解释器.
假设有这样的语句, if ( a ) b; else c; 我们可以这样理解: 如果a成立, 那么执行语句b, 否则执行语句c, 这是常规的理解方式. 我们也可以这样理解: 如果a成立, 那么将过程b的返回值作为整个过程的返回值, 否则将过程c的返回值作为整个过程的返回值. 而对于后一种理解方式又会引出另外一个问题:过程b和过程c是在什么时候被求值的? 如果它们是在判断了if(a)是否成立之后求值,那么其又演变回第一种思维方式,其实质是"正则序"求值, 如果它们是在判断if(a)是否成立之前被求值的, 那么b c 始终都会被求值,无论a是否成立, 它们的求值结果作为if...else 过程的参数参与 if...else 运算. 此时, 实质是"应用序"求值.
对于scheme中 if (包括cond) 采用的是正则序还是应用序,我不好说, 但至少可以说, if 是特殊形式, 不是普通过程, 所以其不会单纯地使用应用序, 所以我们可以看到"不满足条件的分支语句等不到执行". 而上面的new-if是一个普通过程, 所以其是应用序的.
为了验证上面的论证, 编写如下程序:
(define (new-if predicate then-clause else-clause)
(cond (predicate then-clause)
(else else-clause)))
(if (< 2 3) "Yes" "No")
(new-if (< 2 3) "Yes" "NO")
(if (< 2 3) (display "\nyes") (display "no"))
(new-if (< 2 3) (display "\nyes ") (display "no"))
(cond (predicate then-clause)
(else else-clause)))
(if (< 2 3) "Yes" "No")
(new-if (< 2 3) "Yes" "NO")
(if (< 2 3) (display "\nyes") (display "no"))
(new-if (< 2 3) (display "\nyes ") (display "no"))
我们会得到如下结果:
"Yes"
"Yes"
yes
yes no
很明显, 无论判断条件是否成立 new-if中两条分支都得到了执行, 只不过, 只有那个条件成立的分支的求值结果将作为整个过程的最后结果.
回到上面求平方根的问题, 在使用new-if时 ,整个表达式将采用应用序, sqrt-iter将被先求值后代入到cond中, 而在进行sqrt-iter求值时其是递归调用, 并且无法执行到cond语句进行返回, 所以递归将无穷地进行下去.
3, 练习 1.7
在检测good-enough?时使用“变化率”而不是使用绝对数值。
这明显是可行的,并且比使用绝对数值更加科学。使用绝对数值时存在的问题是,如果结果值太大或太小,则无法达到所需的精度或与精度之间的误差太大。
4, 自由变量 和 约束变量
对于自由变量(free variable)和约束变量(bound variable,或称 虚变量 dummy variable),在"形式语言"中有着比较严格的定义,可以参考这里,或翻阅一下大学教材。但理解起来似乎都有些头晕目眩的,如何比较“感性”地判断一个变量时自由的还是被约束的呢(“感性”在很多时候意味着“快速地”,同时也意味着是”没有经过论证的”)?
比如下面的函数:
我们说变量 x 是约束变量, 而 a 是自由变量。
可以通过这样的变量来判断一个变量时自由还是约束的:
(1)自由变量可以替换成一个简单的值(比如数值或对象),而整个函数的还是又意义的,而约束变量则不可以。比如将上面的 a 替换成 3 ,仍是一个完整的求和运算,但如果将 x 替换成 3, 则 3=1 就讲不通了,整个函数表达式失去了原有的意义甚至是错误的。
(2) 自由变量可以提取到函数外部来,而约束变量被约束在函数内部,比如将上述函数表达式中的 a 提取出来,变成:
仍是可以的,但,我们却不可以将 x 提取出来。
另外,约束变量之所以用“约束”一词,是因为其的确被其”上下文(Context)“所约束了,这个约束很可能就是函数所要表达的逻辑意义或数学含义。我无法明确告诉你这里面有什么规则或定义,但是,比如上面的求和运算,x 被“From 1 to 10" 这样的上下文给约束了. 又比如:
![](https://images.cnblogs.com/cnblogs_com/zhouyinhui/express.png)
5, 作用域
关于作用域(Scope)的基本概念和基于具体语言的判定方法就不谈了,不过值得了解的是作用域的两种基本类型:静态作用域(Static Scoping) 和 动态作用域(Dynamic Scoping)。
静态作用域, 我们现在大部分语言(C/C++ C# Java等等)都是使用的这种方式,其名字和对象的绑定发生在编译时,也就是说通过词法分析语法分析等变可以确定,而不需要等到运行时。而在动态作用域里,编译器无法确定名字和对象的绑定,必须等到运行时。
具体的,如何确定这些作用域,推荐看看《程序设计语言——实践之路 》的3.3.1和3.3.2,其讲得非常详细(这里有试读版本:http://book.csdn.net/bookfiles/109/1001098099.shtml)。
注:这是一篇读书笔记,所以其中的内容仅属个人理解而不代表SICP的观点,并随着理解的深入其中的内容可能会被修改