SICP第一章:构造过程抽象(1.3)

本文深入探讨了SICP中的过程抽象,重点介绍了如何使用高阶函数来实现。涵盖1.3章节的内容,包括过程作为参数、lambda表达式构造过程、let表达式创建局部变量,以及过程作为返回值的应用。通过举例,如积分计算、不动点求解、开根号的平均阻尼技术,阐述了如何通过过程来描述一般性方法,并讲解了牛顿法等逼近技术。此外,还提供了多个练习题目以加深理解。
摘要由CSDN通过智能技术生成

1.3 用高阶函数做抽象

1.3.1 过程作为参数

1.高阶过程

以过程作为参数,或者以过程作为返回值,这类能操作过程的过程称之为高阶过程

2.应用于积分

模式一:

(define (sum term a next b)
  (if (> a b)
      0
      (+ (term a)
         (sum term (next a) next b))))

计算:其中,f = x³ ,a=0;b=1
在这里插入图片描述

(define (integral1 f a b dx)
  (define (add-dx x) (+ x dx))
  (* (sum f (+ a (/ dx 2.0)) add-dx b)
     dx))

(define (cube x) (* x x x))

(integral1 cube 0 1 0.01)

>0.24998750000000042   ;;cube在01间积分的精确值是1/4

此方法计算积分并不准确,是一个近似值。练习1.29会给出一个更精确的求积分的方法:辛普森规则

这种函数不能应用于其他语言,1.3.2节说明如和摆脱这种定义

1.3.2 用lambda构造过程

1. 一般形式

(lambda (<formal-parameters>) <body>)

<formal-parameters>为形式参数;<body>为过程体
lambda用于define同样的方式创建过程,此过程不与环境中任何名字相关联。

按如下方式阅读lambda表达式:

(lambda   (x)   (   +     x   4))
该过程  以x为参数  它加起    x 和 4 

2.lambda的应用

1.不需要定义辅助过程
(define (pi-sum a b)
	(sum (lambda (x) (/ 1.0 (* x (+ x 2))))   ;;sum的定义是上面的模式一
			a
			(lambda (x) (+ x 4))
			b))
2.可用作组合式的运算符
((lambda (x y z) (+ x y (* z z))) 1 2 3)

3.用let创建局部变量

1. 一般形式
(let ((<var1> <exp1>)
	  (<var2> <exp2>)
		       :
	  (<varn> <expn>))
	<body>)

可以将它读作

<var1> 具有值 <exp1> 而且
   <var2> 具有值 <exp2> 而且
   :
   <varn> 具有值 <expn> 
	:
在 <body>
2.let表达式被解释为替代如下表达式的另一种语法形式

(对比 lambda可用作组合式的运算符 容易懂)

((lambda (<var1> ...<varn>)
	  <body>)
	<exp1>
	:
	<expn>)

let表达式只是作为基础的lambda表达式的语法外衣罢了

1. 用于与注意

1).let使人能在尽可能接近其使用的地方创建局部变量约束:

(define (test x)
  (+ x (let ((x 6)) (- x 2))))
  
(test 6)
>10

2).变量的值是在let之外计算的

(define (test x)
 (let ((x 3)
       (y (+ x 2)))
   (* x y)))
   
(test 2)
>12

1.3.3 过程作为一般性方法

目的: 如何通过过程去直接描述这些方法

1.通过区间折半寻找方程的根
(define (average x y) (/ (+ x y) 2))  ;求两个数平均值

(define (close-enough? x y) ;;两数之差的绝对值是否足够接近0.001
  (< (abs (- x y)) 0.001))

#|检测过程|#
(define (search f neg-point pos-point)
  (let ((midpoint (average neg-point pos-point)))
    (if (close-enough? neg-point pos-point)
        midpoint
        (let ((test-value (f midpoint)))
          (cond ((positive? test-value)
                 (search f neg-point midpoint))
                ((negative? test-value)
                 (search f midpoint pos-point))
                (else midpoint))))))
#|实现体:给一个函数f 以及零点所在区间的上下限|#
(define (half-interval-method f a b)
  (let ((a-value (f a))
        (b-value (f b)))
    (cond ((and (negative? a-value) (positive? b-value))
           (search f a b))
          ((and (negative? b-value) (positive? a-value))
           (search f b a))
          (else
           (error "值不相符的" a b)))))   ;;;如果不符合上面要求就会报错

(half-interval-method sin 2.0 4.0)
>3.1412353515625
2.找出函数的不动点

不动点: 假如函数上有一点(x y)满足函数f(x)=x 即:x=y,则称此点为该函数的不动点
找不动点的思路: 对于某个函数,通过从某个初始猜测值出发,反复的应用f 即:f(f(f(f(x))))。直到值的变化不大时,就找到了不动点。

(define tolerance 0.00001)  ;;;赋值

(define (fixed-point f first-guess)
  (define (close-enough? v1 v2)
    (< (abs (- v1 v2)) tolerance))
  (define (try guess)
    (let ((next (f guess)))
      (if (close-enough? guess next)
          next
          (try next))))
  (try first-guess))

(fixed-point cos 1.0)
3. 开根号(平均阻尼技术)
(define tolerance 0.00001)

(define (average x y) (/ (+ x y) 2))

(define (fixed-point f first-guess)
  (define (close-enough? v1 v2)
    (< (abs (- v1 v2)) tolerance))
  (define (try guess)
    (let ((next (f guess)))
      (if (close-enough? guess next)
          next
          (try next))))
  (try first-guess))
(define (sqrt1 x)
	(fixed-point (lambda (y) (average y (/ x y)))
				1.0))
(sqrt1 4)
>2.000000000000002

这个过程可以看作求y |-> x/y 的不动点
假如要求根号x,.那我如何让你的猜测值y变换成另一个值使变换后的值接近正确答案,而且可以反复进行。这样 :y = (1/2)(y + x/y) 。运用不动点相加再平均来逼近收敛的方法叫平均阻尼技术

1.3.4 过程作为返回值

1.过程作为返回值

(define (square x) (* x x))

(define (average-damp f)
  (lambda (x) (average x (f x))))
  
((average-damp square) 10)

>55

这里的返回过程用到了上面我们介绍lambda的第二个性质:可用作组合式的运算符

那求平方根可写:

(define (sqrt2 x)
  (fixed-point (average-damp (lambda (y) (/ x y)))
               1.0))

(sqrt2 4)

那求立方根可写:

(define (cube1 x)
  (fixed-point (average-damp (lambda (y) (/ x (square y))))
               1.0))

2. 求导:

将y = x³ 求导为 y = 3x² 。这个过程如何实现?
实现:

f`(x) = (g(x + dx) - g(x)) / dx

(define dx 0.000001)

(define (deriv g)
  (lambda (x)
    (/ (- (g (+ x dx)) (g x))
       dx)))

3. 牛顿法(逼近)

优点: 牛顿法的收敛速度比折半法的收敛速度快得多

公式: f(x) = x - g(x)/g`(x)

证明:
证明图
设x是发f(x )=0的根,选取x0作为x的初始近似值,过点(x0 , f(x0))做曲线y = f(x) 的切线T,
T的方程为:y=f(x0) + f’(x0)(x-x0)
求出T与x轴的交点的横坐标 :x1 = x0 - f(x0)/f’(x0)
,过(x1, f(x1))做曲线y=f(x)的切线,
并求出该切线与x轴焦点的横坐标:x2 = x1 - f(x1)/f’(x1)
称x2为x* 的第二次近似值
重复上次的操作会得到x* 的近似序列。

求平方根:

(define (square x) (* x x))

(define (deriv g)
  (lambda (x)
    (/ (- (g (+ x dx)) (g x))
       dx)))

(define (newton-transform g)
  (lambda (x)
    (- x (/ (g x) ((deriv g) x)))))
    
(define (newtons-method g guess)
  (fixed-point (newton-tansform g) guess))

(define (sqrt3 x)
  (newtons-method (lambda (y) (- (square y) x))    ;;找y = y² - x的不动点
                  1.0))
                  
(sqrt 16)
>4

练习:

练习 1.29

解:

#|求以a为下限,以b为上限,函数f的积分(很精确)|#
(define (sum2 h f a b n k)
  (if (> k n)
      0
      (+ (* (/ (h a b n) 3)
         (cond ((= k 0) (f a))
               ((= k n) (f (+ a (* k (h a b k)))))
               ((= (remainder k 2) 0) (* 2 (f (+ a (* k (h a b n))))))
               (else (* 4 (f (+ a (* k (h a b n))))))))
         (sum2 h f a b n (+ k 1)))))

(define (cube x) (* x x x))

(define (integral2 a b f)
  (define (h a b n) (/ (- b a) n))
  (sum2 h f a b 1000 0))

(integral2 0 1 cube)
练习 1.30

解:

(define (next a) (+ a 1))

(define (term a) (a))

(define (sum term a next b)
  (define (iter a result)
    (if (> a b)
        result
        (iter (next a) (+ (term a) result))))
    (iter a 0))

(define (cube a) (* a a a))

(sum cube 1 next 10)
练习 1.31

解:
递归:

(define (product f a next b)
  (if (> a b)
      1.0
      (* (f a)
         (product f (next a) next b))))
(define (factorial a b f)
  (define (next a) (+ a 1))
  (* (product f a next b) 4))

(define (f x)
    (cond ((= (remainder x 2) 0)
           (/ (+ x 2) (+ x 1)))
          (else
           (/ (+ x 1) (+ x 2)))))

(factorial 1 10000 f)
>3.1417497057379635

迭代:

(define (product f a next b)
  (define (iter a result)
    (if (> a b)
        result
        (iter (next a) (* result (f a)))))
  (iter a 1.0))

(define (factorial a b f)
  (define (next a) (+ a 1))
  (* (product f a next b) 4))

(define (f x)
    (cond ((= (remainder x 2) 0)
           (/ (+ x 2) (+ x 1)))
          (else
           (/ (+ x 1) (+ x 2)))))

(factorial 1 10000 f)
>3.1417497057380084
练习 1.32

解:
递归:
product:

(define (accumulate combiner null-value term a next b)
  (if (> a b)
      null-value
      (combiner (term a)
         (accumulate combiner null-value term (next a) next b))))

(define (factorial a b f)
  (define (next a) (+ a 1))
  (define (combiner x y) (* x y))
  (* (accumulate combiner 1.0 f a next b) 4))


sum:

(define (accumulate combiner null-value term a next b)
  (if (> a b)
      null-value
      (combiner (term a)
         (accumulate combiner null-value term (next a) next b))))
         
(define (sum term a next b)
  (define (next a) (+ a 1))
  (define (combiner x y) (+ x y))
  (accumulate combiner 0 term a next b))

迭代
product:

(define (accumulate combiner null-value term a next b)
  (define (iter a result)
    (if (> a b)
        result
        (iter (next a) (combiner result (term a)))))
  (iter a null-value))

(define (factorial a b f)
  (define (next a) (+ a 1))
  (define (combiner x y) (* x y))
  (* (accumulate combiner 1.0 f a next b) 4))

sum

(define (accumulate combiner null-value term a next b)
  (define (iter a result)
    (if (> a b)
        result
        (iter (next a) (combiner result (term a)))))
  (iter a null-value))
  
(define (sum term a next b)
  (define (next a) (+ a 1))
  (define (combiner x y) (+ x y))
  (accumulate combiner 0 term a next b))
练习 1.33

解:
a).

(define (filtered-accumulate filter combiner null-value term a next b)
  (if (> a b)
      null-value
      (combiner (if (filter a)
                    (term a)
                    null-value)
                (filtered-accumulate filter combiner null-value term (next a) next b))))

(define (divisor a b f)
  (define (next a) (+ a 1))
  (define (combiner x y) (+ x y))
  (define (f x) x)
  (filtered-accumulate prime? combiner 0 f a next b)
  )

b).

(define (filtered-accumulate filter combiner null-value term a next b)
  (if (> a b)
      null-value
      (combiner (if (filter a)
                    (term a)
                    null-value)
                (filtered-accumulate filter combiner null-value term (next a) next b))))

(define (divisor n f)
  (define (next a) (+ a 1))
  (define (combiner x y) (* x y))     ;;;求乘积
  (define (f x) x)                    ;;;为了列出a到b之间每一个数
  (define (filter a) (= (GCD a n) 1)) ;;;此处的filter过滤出与n互素的正整数
  (filtered-accumulate filter combiner 0 f 0 next n)
练习 1.34

解:

(define (f g)
  (g 2))
  
(define (square x) (* x x))

(f square)

(f (lambda (z) (* z (+ z 1))))

(f f)
报错:
application: not a procedure;
 expected a procedure that can be applied to arguments
  given: 2
  arguments...

会报错,因为f过程需要一个过程作为参数,当用f本身作为这个参数时;f过程的内部运行(g 2) 变成了
(f 2),而f过程需要的时过程参数不是常数,所以会报错。

练习 1.35

解:

(define (fixed-point f first-guess)
  (define (close-enough? v1 v2)
    (< (abs (- v1 v2)) 0.0001))
  (define (try guess)
    (let ((next (f guess)))
      (if (close-enough? guess next)
          next
          (try next))))
  (try first-guess))

(define (huang)    
  (fixed-point (lambda (x) (+ (/ 1 x) 1)) 1.0))

(huang)
练习 1.36

解:

(define (fixed-point f first-guess)
  (define (close-enough? v1 v2)
    (< (abs (- v1 v2)) 0.0001))
  (define (try guess)

    (display guess)  ;;;打印出guess的值
    (let ((next (f guess)))
      (newline)      ;;;换行
      (if (close-enough? guess next)
          next
          (try next))))
  (try first-guess))

(define (han)
  (fixed-point (lambda (x)(/ (log 1000) (log x))) 1.1))

(han)
练习 1.37

解:
方法一:

(define (cont-frac n d k)
  (define (iter i result)
    (if (> i k)
        result
        (iter (+ i 1) (/ (n i) (+ (d i) result)))))
  (iter 1 1.0))

(cont-frac (lambda (i) 1.0)  ;;;这里用lambda定义的过程由于是用参数传入,在上面定义cont-frac的时候就相当有了个名字所以使用的时候写成(n i)
           (lambda (i) 1.0)
           11)

方法二(练习1.38建议使用版):

(define (cont-frac n d k)
  (define (iter i null-value)
    (if (> i k)
        null-value
        (/ (n i) (+ (d i) (iter (+ i 1) null-value)))))
  (iter 1 1.0))
  
(cont-frac (lambda (i) 1.0)
           (lambda (i) 1.0)
           11)

当k=11时能保证得到的近似值具有十进制的4位精度。

练习 1.38

解:

(define (cont-frac n d k)
  (define (iter i null-value)
    (if (> i k)
        null-value
        (/ (n i) (+ (d i) (iter (+ i 1) null-value)))))
  (+ (iter 1 1.0) 2))

(cont-frac (lambda (i) 1.0)
           (lambda (i) (cond ((= (remainder (+ i 1) 3) 0) (* 2 (/ (+ i 1) 3)))
                             (else 1)))
           1000)
练习 1.39

解:

(define (tancf d x k)
  (define (iter i null-value)
    (if (> i k)
        null-value
        (/ (square x) (- (d i) (iter (+ i 1) null-value)))))
  (* (iter 1 1.0) x))

(define (square x) (* x x))
(define (tan-cf x k)
  (define (d i)
    (- (* 2 i) 1))
  (tancf d x k))

(tan-cf 1 10000)
练习 1.40

解:

#|求平方|#
(define (square x) (* x x))
(define dx 0.001)

#|求导|#
(define (deriv g)
  (lambda (x)
    (/ (- (g (+ x dx)) (g x))
       dx)))

#|牛顿法逼近零点|#
(define (newton-transform g)
  (lambda (x)
    (- x (/ (g x) ((deriv g) x)))))

#|fixed-point 该过程产生出不动点的过程 |#
(define (fixed-point f first-guess)
  (define (close-enough? v1 v2)
    (< (abs (- v1 v2)) 0.00001))
  (define (try guess)
    (let ((next (f guess)))
      (if (close-enough? guess next)
          next
          (try next))))
  (try first-guess))

#|返回这个过程|#
(define (newtons-method g guess)
  (fixed-point (newton-transform g) guess))

(define (cubic a b c)
  (lambda (x) (+ (* x x x) (* a x x) (* b x) c)))
#|给a b c 赋值|#
(newtons-method (cubic 1 1 1) 1)

>-1.0000000001211478
练习 1.41

解:

(define (double g)
  (lambda (x) (g (g x))))

(define (inc x) (+ x 1))

((double inc) 1)

(((double (double double)) inc) 5)

>3
>21
练习 1.42

解:

(define (inc x) (+ x 1))

(define (square x) (* x x))

(define (compose2 a b) 
  (lambda (x)
    (a (b x))))

((compose2 square inc) 6)
练习 1.43

解:
迭代:

(define (square x) (* x x))

(define (repeated f n)
  (define (iter x n)
      (if (<= n 0)
          x
          (iter (f x) (- n 1))))
  (lambda (x)
    (iter x n)))
((repeated square 2) 5)
>625

递归:

(define (square x) (* x x))

(define (repeated f n)
  (define (iter x n)
      (if (<= n 0)
          x
          (f (iter x (- n 1)))))
  (lambda (x)
    (iter x n)))
((repeated square 2) 5)
>625
练习 1.44

解:

(define dx 0.001)
(define (square x) (* x x))
(define (smooth f)
  (lambda (x)
   (/ (+ (f (- x dx)) (f x) (f (+ x dx))) 3)))


(define (repeated f n)
  (define (iter x n)
      (if (<= n 0)
          x
          (f (iter x (- n 1)))))
  (lambda (x)
    (iter x n)))

(define (smooth-repeated f n)
  (lambda (x)
    (((repeated smooth n) f) x)))
((smooth-repeated square 10) 5) ;;;f函数经过10次平滑后产生的过程应用到5上
>25.00000666666665

以后补下面两题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值