• SICP学习笔记(1.3.4)


                                               SICP学习笔记(1.3.4)
                                                    周银辉

    1,过程作为返回值

    在1.3中我们明白了高阶函数之后,“用一个过程作为另外一个过程的返回值”则是稀松平常的事情了,比如下面的代码:
    (define (f x)
      (+ x 1))

    (define (g) f)

    ((g) 2)

    函数g没有参数,其返回值为函数f,所以((g) 2)就运算结果就是(f 2),最后运算结果为3。

    上面是用一个已命名的函数作为返回结果的,相应的,也可以将一个“匿名过程”作为结果返回,这里的“匿名过程”也就是我们的Lambda表达式,所以上面的代码可以改造成:
    (define (g)
      (lambda (x) (+ x 1)))

    ((g) 2)
    那么((g) 2)的运算结果就是((lambda (x) (+ x 1)) 2),最后运算结果为3。

    2,牛顿法

    学到这里,你可能需要复习一下高等数学的基本内容,包括“导数”和“微分”,高数的在线教材可以在这里找到:http://sxyd.sdut.edu.cn/gaoshu1/index.htm

    关于牛顿法的介绍可以看这里:http://en.wikipedia.org/wiki/Newton%27s_method ,下面是程序:

    (define (close-enough? v1 v2)
      (< (abs (- v1 v2)) 0.000000001))

    ;定义不动点函数
    (define (fixed-point f first-guess)
      (define (try guess step-count)
           (let ((next (f guess)))
             (if (close-enough? guess next)
                 next
                 (try next (+ step-count 1)))))
       (try first-guess 0))

    ;定义导数函数
    (define (D f)
      (lambda (x dx) (/ (- (f (+ x dx))  (f x)) dx)))

    ;牛顿法
    (define (newton g first-guess)
      (fixed-point (lambda (x) (- x (/ (g x) ((D g) x 0.000000001)))) first-guess))

    ;平方
    (define (square x)
      (* x x))

    ;定义开方,来测试下牛顿法
    (define (sq x)
      (newton (lambda (y) (- (square y) x)) 1.0))

    (sq 5)

    3,“一等公民”

    这里列出了程序语言中作为“一等公民”的语言元素所具备的几个“特权”:

    • 可以用变量命名
    • 可以作为过程参数
    • 可以作为过程返回结果
    • 可以被包含在数据结构中

    4,练习1.40

    求三次方程 x^3 + ax^2 + bx + c 的零点。

    首先,证明 函数f(x) = x^3 + ax^2 + bx + c 是“可微”的:
    由可导和可微的性质知道,可导和可微互为充要条件,所以,要证可微我们可以先证可导,
    f ’ (x) = (x^3)’ + (ax^2)’ + (bx)’ + (c)’
            = 3x^2 + 2ax + b
    所以f(x)的导数存在,那么f(x)可导,其必定可微。

    其次,利用“牛顿法”:如果f(x)是可微函数,那么f(x)=0的一个解就是函数(x – f(x)/df(x)的一个不动点,其中df(x)是f(x)的导数。所以我们可以轻松得到下面的代码:

    (define (close-enough? v1 v2)
      (< (abs (- v1 v2)) 0.000000001))

    ;定义不动点函数
    (define (fixed-point f first-guess)
      (define (try guess step-count)
           (let ((next (f guess)))
             (if (close-enough? guess next)
                 next
                 (try next (+ step-count 1)))))
       (try first-guess 0))

    ;定义导数函数
    (define (D f)
      (lambda (x dx) (/ (- (f (+ x dx))  (f x)) dx)))

    ;牛顿法
    (define (newton g first-guess)
      (fixed-point (lambda (x) (- x (/ (g x) ((D g) x 0.000000001)))) first-guess))

    ;定义cubic函数,也就是我们题目中所谓的f(x)
    (define (cubic a b c)
      (lambda (x) (+ (* x x x) (* a x x) (* b x) c)))

    ;随便定义几个系数
    (define a 3)
    (define b 5)
    (define c 8)
    (define result (newton (cubic a b c) 1.0))

    ;定义一个验证过程,让其验证得到的解,是否让方程成立
    (define (validate x)
      (= 0 (+ (* x x x) (* a x x) (* b x) c)))

    ;输出结果
    result

    ;验证结果
    (validate result)

    比如上面我们计算 x^3 + 3x^2 + 5x + 8 = 0, 其一个解为:-2.3282688556686084

    5,练习1.41

    double 将函数f计算两次,那么 (double double)将计算4次,(double (double double))将计算14次,所以返回值应该是21,可以运行下面的代码试试 :

    (define (double f)
      (lambda (x) (f (f x))))

    (define (inc a) (+ a 1))

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

    6,练习1.42

    关于复合函数,非常简单,直接贴答案了:

    (define (inc a) (+ a 1))
    (define (square a) (* a a))

    (define (compose f g)
      (lambda (x) (f (g x))))

    ((compose square inc) 6)

    7,练习1.43

    f(f(f…(f(x)…))实际上就是函数 f 被复合N次:

    (define (inc a) (+ a 1))
    (define (square a) (* a a))

    (define (compose f g)
      (lambda (x) (f (g x))))

    (define (repeated f count)
      (define (repeated-inner f step)
        ;如果复合到了指定的次数,则返回被复合后的函数
        (if (= step count)
            f
            ;否则,再被复合一次
            (repeated-inner (compose f f) (+ step 1))))
      (lambda (x) ((repeated-inner f 1) x)))

    ((repeated square 2) 5)

    8,练习1.44

    ;定义复合函数
    (define (compose f g)
      (lambda (x) (f (g x))))

    ;定义N次复合函数
    (define (repeated f count)
      (define (repeated-inner f step)
        (if (= step count)
            f
            (repeated-inner (compose f f) (+ step 1))))
      (lambda (x) ((repeated-inner f 1) x)))

    ;定义平滑函数
    (define (smooth f)
      (lambda (x) (/
                      (+ (f (- x 0.0001)) (f x) (f (+ x 0.0001)))
                      3)))

    ;定义N次平滑函数
    (define (smooth-n f count)
      (repeated (smooth f)  count))

    9,练习1.45

    基本上全部利用以前的劳动成果:不动点、平均阻尼、复合函数等,来球N次方根

    (define (close-enough? v1 v2)
      (< (abs (- v1 v2)) 1.0E-20))

    ;定义不动点函数
    (define (fixed-point f first-guess)
      (define (try guess step-count)
           (let ((next (f guess)))
             (if (close-enough? guess next)
                 next
                 (try next (+ step-count 1)))))
       (try first-guess 0))

    ;定义复合函数
    (define (compose f g)
      (lambda (x) (f (g x))))

    ;定义N次复合函数
    (define (repeated f count)
      (define (repeated-inner f step)
        (if (= step count)
            f
            (repeated-inner (compose f f) (+ step 1))))
      (lambda (x) ((repeated-inner f 1) x)))

    ;定义x的n次方
    (define (power x n)
      (define (power-inner step result)
        (if (= step n)
            result
            (power-inner (+ step 1) (* result x))))
      (power-inner 0 1))

    ;定义平均阻尼函数
    (define (average v1 v2)
      (/ (+ v1 v2) 2.0))

    ;平均阻尼的Currying版本
    (define (avg v1)
      (lambda (v2) (/ (+ v1 v2) 2.0)))

    ;定义N次平均阻尼函数
    (define (average-n v1 v2 n)
      ((repeated (avg v1) n) v2))

    ;定义平方根
    (define (root x)
      (fixed-point (lambda (y) (average y (/ x y))) 1.0))

    ;定义N次方根
    (define (root-n x n)
      (fixed-point (lambda (y) (average-n y (/ x (power y (- n 1))) n)) 1.0))

    ;测试,计算2的平方根
    (root 2)
    ;测试,计算12的3次方根
    (root-n 12 3)

    值得注意的地方是定义N次平均阻尼函数,由于我们定义的(Repeated f count)时默认了函数f只带一个参数,所以不能直接将带有两个参数的average函数拿去做复合运算,所以我们需要将其Currying化为一个参数,也就是我们的avg版本。另外,上面在使用average-n时我将其平均阻尼次数设置为了n(也就是方根的次数),至于刚好多少次就可以收敛,我没有去试验。

    10,练习1.46

    直接一个尾递归将题目的意思翻译成代码就可以了:

    (define (interative-improve isGood improveIt)
      (lambda (x)
        ;如果值足够好,则返回值
        ( if (isGood x)
             x
             ;否则,将修正后的值(improveIt x)拿去继续计算
             ((interative-improve isGood improveIt) (improveIt x)))))

    ;以下几个函数为测试函数
    (define (good-enough? x)
      (< x 1.0E-10))

    (define (improve x)
      (* x 0.1))

    ((interative-improve good-enough? improve) 5.0)

    注:这是一篇读书笔记,所以其中的内容仅属个人理解而不代表SICP的观点,并随着理解的深入其中的内容可能会被修改

  • 相关阅读:
    Dos命令快速设置ip、网关、dns地址
    远程桌面连接保存登陆用户以及密码(凭据)备份方法
    如何启用windows8, windows10中被停用的远程桌面,如何连接windows10远程桌面?
    通过日志恢复SQL Server的历史数据
    http://sourceforge.net/projects/rtspdirectshow/
    iphone上实现H264 硬编码
    利用lipo编译合并iPhone模拟器和真机通用的静态类
    在iOS上使用ffmpeg播放视频
    基于.Net的单点登录(SSO)解决方案
    java实现简单的单点登录
  • 原文地址:https://www.cnblogs.com/zhouyinhui/p/1586882.html
Copyright © 2020-2023  润新知