SICP 学习笔记 (Chapter 1)
第一章 构造过程抽象
1.1 程序设计的基本元素
关注语言的三个机制:
- 基本表达形式,用于表示语言所关心的最简单的个体。
- 组合的方法,通过它们可以从较简单的东西出发构造出复合的元素。
- 抽象的方法,通过它们可以为复合对象明明,并将它们当作单元去操作。
操作处理的要素:过程和数据(二者并非严格分离)。
1.1.1 表达式
1.1.2 命名与环境
命名
(define pi 3.1415926)
命名是一种最初步的抽象。
这种特征鼓励人们采用递增的方式去开发和调试程序。
1.1.3 组合式的求值
求值过程是递归的。
define
一类的求值规则例外成为特殊形式。
1.1.4 复合过程
(define (square x) (* x x))
过程体可以是一系列的表达式,解释器对其进行顺序求值,返回最后一个表达式的值。
1.1.5 过程应用的代换模型
- 代换的作用只是帮助理解,并不是对解释器实际工作方式的具体描述。
- 代换模型是最简单(仅指理解,非指数学定义)的理解模型,后面将会讨论更复杂的过程应用耐磨性。
1.1.6 条件表达式和谓词
解释器认为一切非 #f
的值均为真。本书中使用 true
和 false
代替 #t
和 #f
。
cond
特殊形式
(cond (<p_1> <e_1>)
(<p_2> <e_2>)
...
(<p_n> <e_n>)
(else <e>))
其中每个 <e> 表达式都可以是表达式序列。
if
特殊形式
(if <predicate> <consequent> <alternative>)
其中 <consequent> 和 <alternative> 都只能是单个表达式。
逻辑复合运算符
(and <e_1> ... <e_n>)
按顺序求值,若求得假则返回假,否则返回最后一个表达式的值。
(or <e_1> ... <e_n>)
按顺序求值,返回第一个为真的值,否则返回假。
(not <e>)
逻辑非。
注意:and
和 or
都是特殊形式(因为它们的子表达式不一定都求值),not
则是一个普通的过程。
1.1.7 实例:采用牛顿法求平方根
// 这一节开头提到的“说明性描述”和“行动性描述”的区别很有意思。
1.1.8 过程作为黑箱抽象
我们可以将一个问题分解成若干个子问题,每个子问题由一个过程来解决。当我们使用这个过程时,不关注它的实现细节,只关注它具备的功能,也就是说这些过程更应该被称为过程的抽象,也就是过程抽象。
练习
练习 1.1
10
12
8
3
6
19
#f
4
16
6
16
练习 1.2
(/
(+ 5
4
(- 2
(- 3
(+ 6 (/ 4 5)))))
(* 3 (- 6 2) (- 2 7)))
练习 1.3
(define (sum-of-largest-two a b c)
(cond
((and (< a b) (< b c))
(+ b c))
((and (> a b) (> b c))
(+ a b))
((and (> a b) (< b c))
(+ a c))
(else
(if (> a c)
(+ a b)
(+ b c)))))
练习 1.4
返回 a
加 b
的绝对值之和。
练习 1.5
若是应用序则将无限循环求值 (test 0 (p))
,若是正则序则可以求得结果 0
。
练习 1.6
对于 new-if
函数,在调用时会将其三个参数分别求值后代入(应用序),而 if
特殊形式只会先求出 predicate
的值,然后根据其 truthiness 对两个子句之一求值。
所以 Eva 的过程会陷入无限循环。
练习 1.7
对于极小的数,预先设定的误差值 0.0001
显然过小,可能会在逼近确切值之前就停止;
对于极大的数,因为计算机中的浮点数有精度限制,有可能在 guess
的值达到精度内所能表示的最接近的值时误差依然大于 0.0001
,从而使程序无法停止。
(define (good-enough? guess x)
(= (improve guess x) x))
练习 1.8
(define (cubic-root-iter guess x)
(if (good-enough? guess x)
guess
(cubic-root-iter (improve guess x)
x)))
(define (improve guess x)
(/ (+ (/ x
(square guess))
(* 2 guess))
3))