首页 > 学院 > 开发设计 > 正文

SICP学习·第一章·第一节

2019-11-08 02:21:37
字体:
来源:转载
供稿:网友

第一章 构造过程抽象

第一章 构造过程抽象1程序设计的基本元素11表达式12命名和环境13 组合式的求值14 复合过程15 过程应用的代换模型16 条件表达式和谓词17 实例采用牛顿法求平方根18过程作为黑箱抽象

1.1程序设计的基本元素

为了将简单的认识组合成复杂的认识,每一种强有力的语言都会提供的三种机制: 基本表达式:代表该语言所关心的最简单的实体。组合:从较为简单的实体出发,构造出复合实体。抽象:为复合实体命名并将其作为一个整体进行操作。

1.1.1表达式

本节第一次讲到的scheme语法:;;基本表达式:数,算数运算符;;组合表达式:(<运算符> n个<运算对象>);;其中运算对象是一个表达式。

1.1.2命名和环境

本节第一次讲到的scheme语法:定义对象:(define <标识符> <表达式>);;进行了define后就可以直接通过对应的标识符来引用表达式了。;;而为了实现通过标识符引用表达式,解释器必须拥有某种存储能力来保证标识符和表达式的对应,这种存储被称为环境。

1.1.3 组合式的求值

scheme对于组合式的求值方法: 获得组合表达式中的子表达式的值。使用运算对象作为运算符的参数,对组合式进行求解。

1.1.4 复合过程

本节第一次讲到的scheme语法:;;定义过程:(define (<标识符> <该过程的形式参数>) <表达式>)

1.1.5 过程应用的代换模型

复合过程应用的计算模型: 将过程的形式参数替换为过程所在表达式中的运算对象,再进行求值(只是为了便于理解,事实上并不是解释器的具体工作方式)。应用序与正则序: 正则序:先将作为参数的表达式代入过程中,展开后一一求值。 应用序:先求出作为参数的表达式的值,再代入过程中。 由于参数在过程中可能被多次用到,使用正则序会导致多次展开而重复求值,降低效率。 在超出替换方式模拟模型的过程范围后,正则序的操作将会复杂很多(本小节没有具体说明)。 但有时正则序可以成为特别有用的工具(本小节没有具体说明)。

1.1.6 条件表达式和谓词

本节第一次讲到的scheme语法:;;基本表达式:逻辑表达式#t和#f,谓词<,>,=,复合运算符and,or,not;;条件判断表达式:(cond n个(<条件判断表达式> <操作表达式>));;运算方法:;;从第一个条件判断表达式开始查找,直到查找到条件判断表达式为真的表达式,执行其对应的操作表达式。;;条件判断表达式:(if <条件判断表达式> <操作表达式1> <操作表达式2>);;运算方法:;;若条件判断表达式为真则执行操作表达式1,否则执行操作表达式2。练习1.1:求对于每个表达式的输出结果10;;Value: 10(+ 5 3 4);;Value: 12(- 9 1);;Value: 8(/ 6 2);;Value: 3(+ (* 2 4) (- 4 6));;Value: 6(define a 3)(define b (+ a 1))(+ a b (* a b));;Value: 19(= a b);;Value: #f(if (and (> b a) (< b (* a b))) b a);;Value: 4(cond ((= a 4) 6) ((= b 4) (+ 6 7 a)) (else 25));;Value: 16(+ 2 (if (> b a) b a));;Value: 6(* (cond ((> a b) a) ((< a b) b) (else -1)) (+ a 1));;Value: 16练习1.2:将下面的表达式变为前缀形式(5+4+(2-(3-(6+4/5))))/(3*(6-2)*(2-7))(/ (+ 5 4 (- 2 (- 3 (+ 6 (/ 4 5))))) (* 3 (- 6 2) (- 2 7)));;Value: -37/150练习1.3:请定义一个过程,以三个数为参数,返回其中较大的两个数之和(define (PRoduce a b c) (cond ((and (< a b) (< a c)) (+ b c)) ((and (< b a) (< b c)) (+ a c)) ((and (< c a) (< c b)) (+ a b)) ))(produce 5 8 3);;Value: 13练习1.4:请仔细考察上面给出的允许运算符为复合表达式的组合式的求值模型,根据对这一模型的认识描述下面过程的行为(define (a-plus-abs-b a b) ((if (> b 0) + -) a b));;若参数b大于0,则运算符为+,运算结果为a+b,否则运算结果为a-b。练习1.5:若某个解释器采用的是应用序求值,Ben会看到什么样的情况?如果解释器采用正则序求值,他又会看到什么情况?请对你的回答做出解释(define (p) (p))(define (test x y) (if (= x 0) 0 y))(test 0 (p));;若解释器采用应用序求值:;;解释器在调用test时,优先求出参数的值,其中(p)会不断求值得到它自己,进入死循环。;;若解释器采用正则序求值:;;(test 0 (p))会展开为(if (= 0 0) 0 (p)),由于判断表达式(= 0 0)值为#t,将直接得到0而不会去求(p)的值。

1.1.7 实例:采用牛顿法求平方根

实例代码(define (sqrt-iter guess x) (if (good-enough? guess x) guess (sqrt-iter (improve guess x) x)))(define (improve guess x) (average guess (/ x guess)))(define (average x y) (/ (+ x y) 2))(define (good-enough? guess x) (< (abs (- (square guess) x)) 0.001))(define (sqrt x) (sqrt-iter 1.0 x))练习1.6:定义过程new-if如下,若将牛顿法sqrt-iter过程中的if替换为new-if,计算平方根时将会发生什么(define (new-if predicate then-clause else-clause) (cond (predicate then-clause) (else else-clause)));;由于解释器采用的是应用序求值,在使用new-if过程时将会求else-clause的值,而每次计算else-clause的值时sqrt-iter过程都会调用自身,从而导致死循环。练习1.7:解释并用例子说明原代码对于很大的数和很小的数来说是不适合的,并设计通过检测两次迭代之间差与猜测值的比值来确定迭代结束的方法并用例子检测其对于很大和很小的输入是否适用(sqrt 0.00000001);;Value: .03125010656242753;;true answer: 0.0001;;对于较小的数而言,正确答案本身与原代码中的0.001相近或远小于,此时猜测值的误差过大(sqrt 4000000000000000000000000000000000000000000000000000000000000);;死循环;;对于较大的数而言,由于精度限制,可能即使与答案最近的两个数与答案的差也大于0.001,此时good-enough过程永远不可能为真。(define (good-enough? old-guess new-guess) (< (abs (/ (- new-guess old-guess) old-guess)) 0.001))(define (sqrt-iter guess x) (if (good-enough? guess (improve guess x)) guess (sqrt-iter (improve guess x) x)));;未涉及的过程与原过程相同(sqrt 0.00000001);;Value: 1.0000040611237676e-4;;true answer: 0.0001;;答案较为准确(sqrt 4000000000000000000000000000000000000000000000000000000000000);;Value: 2.000157691333889e30;;true answer: 2e30;;答案较为准确练习1.8:根据求立方根的牛顿迭代公式((x/y^2)+2*y)/3(y为猜测值)得到求立方根的过程。(define (improve guess x) (/ (+ (/ x (* guess guess)) (* 2 guess)) 3));;未涉及的过程与原过程相同(sqrt 8);;Value: 2.000004911675504(sqrt 27);;Value: 3.001274406506175

1.1.8过程作为黑箱抽象

本节第一次讲到的scheme语法:;;对于define的提示:;;define过程中还可以定义define过程,如可以将上节牛顿迭代法的代码改为:(define (sqrt x) (define (good-enough? guess x) (< (abs (- (square guess) x)) 0.001)) (define (improve guess x) (average guess (/ x guess))) (define (sqrt-iter guess x) (if (good-enough? guess x) guess (sqrt-iter (improve guess x) x))) (sqrt-iter 1.0 x));;此时外部仅可调用sqrt过程而无法调用其他过程;;此外在上面的代码中,可以将整个过程始终保持不变的变量x省略,从而简化块内过程传递的参数:(define (sqrt x) (define (good-enough? guess) (< (abs (- (square guess) x)) 0.001)) (define (improve guess) (average guess (/ x guess))) (define (sqrt-iter guess) (if (good-enough? guess) guess (sqrt-iter (improve guess)))) (sqrt-iter 1.0))
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表