zoukankan      html  css  js  c++  java
  • SICP学习笔记(1.3.1)

                                        SICP学习笔记(1.3.1)        
                                                        周银辉

    1,高阶函数

    从小学数数 1 2 3 4 5,所以当有一天老师告诉你,它们称之为“自然数”时,你的脸上便没有任何吃惊的表情,因为在你看来它们是那么的“自然”。同样的,如果你开始便是接触的是函数式编程(而不是大学C语言)的话,那么在这里提到高阶函数,你的表情也应该是非常淡然,而不是迷惑。
    在命令式编程语言中,我们习惯于将数、变量、对象作为函数参数与返回值;同样地,在函数式语言中,我们同样习惯于将 函数 作为 另一函数的参数或返回值(也可以是自身的参数或返回值,如果是递归的话),我们将这种“以函数为参数或返回值的函数”称为“高阶函数”或“高阶过程”。由于在函数式语言中,你所遇到的一切均是函数,(比如数字 3,它是 λfx.f (f (f x)) 这样的函数,在1.3.2讲lambda和丘奇数的时候会说道这个东西),所以,将函数作为参数或返回值则是最正常不过的事情了,它是那么的“自然”。
    更多的,关于高阶函数的定义可以参考这里:http://en.wikipedia.org/wiki/Higher-order_function

    2,Currying 

    这个应该放到1.3.2来说,但很奇怪的是,本节练习题1.33的最后一个小问却需要这个知识点,所以在这里简单提一下:Currying就是将拥有多个参数的函数化简成只有一个参数的形式。
    比如在我们的印象中,假设我们需要这样定义两个数的求和运算: (define (add a b) (+ a b)) , 这需要对add方法传入两个参数,比如 (add 2 3); 如果我们只允许add 带一个参数,那应该怎么办呢? 我们应该采用Currying这个技巧编写出下面的代码:
    (define (add a)
      (lambda (b) (+ a b)))
    此后,调用add方法就只需要传入一个参数了,比如 (((add 2) 3)
    如果你还有所疑惑的话,不妨看看 Lambda calculus 以及 Continuation 的相关知识点。或者看看我接下来会写的“SICP学习笔记1.3.2”

    3,练习1.29

    用辛普森规则求积分,比较简单,基本上是将辛普森规则翻译成Scheme代码就可以了:

    (define (sum term a next b)

      (if (> a b)

          0

          (+ (term a)

             (sum term (next a) next b))))

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

    (define (F f a b n)

      (define h (/ (- b a) n))

      (define (y k) (f (+ a (* k h))))

      (define (term i)

        (+ (y (- (* 2 i) 2))

           (* 4 (y (- (* 2 i) 1)))

           (y (* 2 i))))

      (define (next i) (+ i 1))

      (/ (* h (sum term 1 next (/ n 2))) 3))

    我用这段代码计算了一下几个值:
    (F cube 0 1 10.0)
    (F cube 0 1 100.0)
    (F cube 0 1 1000.0)
    (F cube 0 1 1000000.0)

    运算结果:
    0.25000000000000006
    0.2500000000000001
    0.2500000000000001
    0.2499999999999972

    4,练习1.30

    先理解过程中各个参数的意思:
    sum,求和运算
    term,一个函数,(term a)就相当于数学中的F(a)
    a,求和运算中自变量的起始点
    b,求和运算中自变量的结束点
    next,步进函数,即描述自变量如何从当前值步进到下一个值

    OK,要完成这个练习,我们不妨先写一个专门针对连续整数的求和过程,也就是说,(terms a)的值为a,相当于数学中的f(x)= x ; 并且 (next n)为 n+1, 它的求和过程的尾递归版本如下:
    (define (sum a b)
      (sum-iter a b 0))

    (define (sum-iter a b c)
      (if (> a b)
          c
          (sum-iter (+ a 1) b (+ a c))))

    关于如何建立该过程,请参考 SICP学习笔记(1.2.1 ~ 1.2.2) 中的“尾递归”节

    那么按照上面的方式“依葫芦画瓢”,便可建立如下通用的求和版本:
    (define (sum term a next b)
      (if (> a b)
          0
          (+ (term a)
             (sum term (next a) next b))))

    (define (sum-iter term a next b cumulater)
      (if (> a b)
          cumulater
          (sum-iter term (next a) next b (+ (term a) cumulater))))

    5,练习1.31

    利用高阶函数求Pi(∏ )

    首先,按照求和的方法“依葫芦画瓢”,可以写出一下“求积”版本:
    (define (product term a next b)
      (product-iter term a next b 1))

    (define (product-iter term a next b cumulater)
      (if (> a b)
          cumulater
          (product-iter term (next a) next b (* (term a) cumulater))))

    第n项的分子:
    (define (den n)
      (cond ((= n 1) 2.0)
            ((even? n) (+ 2.0 n))
            (else (den (- n 1)))))

    第n项的分母:
    (define (num n)
      (cond ((even? n) (num (- n 1)))
            (else (+ n 2.0))))

    第n项,函数F(n):
    (define (F n)
      (/ (den n) (num n)))

    步进函数:
    (define (increase a) (+ a 1))

    然后就可以对pi求值了(我这里计算了前1亿项):
    (* 4.0 (product F 1 increase 100000000))

    计算结果(大概花了一分钟):
    3.1415926692944294

    6,练习1.32

    没什么好说的,直接给的答案了:

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

      (accumulate-iter combiner term a next b null-value))

    (define (accumulate-iter combiner term a next b result)

      (if(> a b)

         result

         (accumulate-iter combiner term (next a) next b (combiner (term a) result))))

    (define (F a) a)

    (define (increase a) (+ a 1))

    ;为验证正确性,下面两个为测试函数
    (accumulate + 0 F 1 increase 5)

    (accumulate * 1 F 1 increase 5)

    7,练习1.33

    “过滤器”在2.2.3中会提到,这里可以简单地想象成一个检测装置:对于给定值a,如果满足给定条件condition,则返回值本身,否则返回空值 null-value,所以

    ;定义过滤器,这里我将其值打印出来了,以便看到过滤过程
    (define (filter condition null-value a)
      (cond ((condition a) (begin (display a) (display "; ") a))
            (else null-value)))

    ;定义filtered-accumulate,其为练习1.32的accumulate增强版
    (define (filtered-accumulate combiner null-value term a next b filter-condition)
      (accumulate-iter combiner term a next b null-value null-value filter-condition))

    ;定义filtered-accumulate的尾递归版本
    (define (accumulate-iter combiner term a next b null-value result filter-condition)
      (if(> a b)
         result
         (accumulate-iter combiner term (next a) next b null-value
                          (combiner
                           (filter filter-condition null-value (term a)) result)
                          filter-condition)))

    ;定义素数检测函数
    (define (prime? n)
      (= n (smallest-divisor n)))

    (define (divides? a b)
      (= (remainder b a) 0))

    (define (square a)
      (* a a))

    (define (find-divisor n test-divisor)
      (cond ((> (square test-divisor) n) n)
            ((divides? test-divisor n) test-divisor)
            (else (find-divisor n (+ test-divisor 1)))))

    (define (smallest-divisor n)
      (find-divisor n 2))

    ;定义小于N并且与N互素的检测函数
    (define (gcd-n? n)
      (lambda(a)
          (and (< a n) (= (gcd a n) 1))))

    ;定义恒等函数 f(x)=x
    (define (F a) a)

    ;定义增长率
    (define (increase a) (+ a 1))

    ;计算1~100间的素数之和
    (filtered-accumulate + 0 F 1 increase 100 prime?)

    ;计算小于100并且与100互素的正整数之乘积
    (filtered-accumulate * 1 F 1 increase 100 (gcd-n? 100))

    注意到上面定义的“小于N并且与N互素的检测函数”,其用到了我们上面所说的“currying”技巧,其仅仅带有一个参数n,如果我们按照常规的方式书写:
    (define (gcd-n? n a)
      (and (< a n) (= (gcd a n) 1)))
    其带了两个参数,我们很快就会发现你无法带入到我们的“过滤器”函数中:
    (define (filter condition null-value a)
      (cond ((condition a) (begin (display a) (display "; ") a))
            (else null-value)))
    因为(condition a)是只带一个参数的。

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




  • 相关阅读:
    1.4.2.3. SETUP(Core Data 应用程序实践指南)
    1.4.2.2. PATHS(Core Data 应用程序实践指南)
    1.4.2.1. FILES(Core Data 应用程序实践指南)
    1.4.2. 实现 Core Data Helper 类(Core Data 应用程序实践指南)
    1.4.1. Core Data Helper 简介(Core Data 应用程序实践指南)
    1.4. 为现有的应用程序添加 Core Data 支持(Core Data 应用程序实践指南)
    1.3.2. App Icon 和 Launch Image(Core Data 应用程序实践指南)
    1.3.1. 新建Xcode项目并设置故事板(Core Data 应用程序实践指南)
    php验证邮箱是否合法
    如何使js函数异步执行
  • 原文地址:https://www.cnblogs.com/zhouyinhui/p/1576637.html
Copyright © 2011-2022 走看看