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的观点,并随着理解的深入其中的内容可能会被修改




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
"SICP中文版"是指计算机科学经典教材《Structure and Interpretation of Computer Programs》(计算机程序的构造和解释)的中文翻译PDF版。这本教材由麻省理工学院的Harold Abelson和Gerald Jay Sussman等人编写,是计算机科学领域中一本重要的教材。 "SICP中文版PDF"提供了更方便的学习方式。无论是学生、程序员还是计算机科学爱好者,都可以在任何时候通过电子设备访问和学习这本教材。使用PDF格式的好处是可以在不同的平台上都能打开和阅读,而不受限于特定的操作系统或设备。 通过"SICP中文版PDF",读者可以学习计算机科学的基本原理和概念,如过程、数据抽象、递归、高阶函数、并发等。这本教材以Scheme语言为示例,帮助读者理解计算机程序的结构、设计和解释。通过逐步的案例和练习,读者可以锻炼解决问题和编写高质量代码的能力。 "SICP中文版PDF"也提供了沟通和讨论的平台。读者可以通过在线社群或论坛,与其他人分享学习心得、解答疑问和参与讨论。这为读者提供了一个学习交流的机会,促进了学习者之间的互动和共同成长。 总之,"SICP中文版PDF"是一本经典的计算机科学教材的中文翻译版本,使得更多的读者可以方便地学习和掌握其中的知识。无论是对于计算机科学专业的学生还是对计算机科学感兴趣的人,这本教材都是一本很好的参考书,并提供了丰富的实例和练习,让读者深入理解计算机程序的核心概念和设计原则。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值