SICP 第一章笔记

这段时间断断续续把第一章和第二章看完了,记录下重点与感想当作复习吧。

以及第一章大部分的习题答案,基本都在mit-scheme 9.2里跑过了,不过不保证完全正确嗯(

构造过程抽象

从简单的数值计算程序,到抽象的Web服务器、操作系统,我们编写它们时的目的都是相同的,即构造出一种计算过程,让这些过程去操作一些被称为数据的抽象事物。

我们使用程序设计语言,通过符号表达式的形式编排出程序,来描述我们希望计算机完成的计算过程

程序设计的基本元素

计算过程是复杂的,而人不善于处理过于复杂的事物。为此,语言不应仅仅是一种指挥计算机执行任务的方式,更应是一种框架,这种框架让我们能更方便地组织计算过程的思想。

为了做到这一点,一个强大的语言必须提供三种机制:

  • 基本表达形式,语言内的最简单个体
  • 组合的方法,将个体组合出复合元素
  • 抽象的方法,将复合元素作为个体操作

过程应用的求值顺序

求值一个组合表达式时,我们可以采用两种策略:

  • 应用序,首先对运算符和各个运算对象求值,然后将得到的过程应用于得到的实际参数;即先求值再应用
  • 正则序,不先求出运算对象的值,直到实际需要它们的值时再去做;即先完全展开后归约

这两种求值顺序不是等价的,Lisp采用应用序求值。

过程作为黑箱抽象

一个问题可以分解为若干子问题,每个子问题都可以通过一个独立的过程完成,最后整个问题可以看作是一族过程的集合。

分解中的每一个过程完成了一件可以清楚标明的工作,隐藏起一些细节,让过程调用者不必自己去写这些过程。

过程与他们所产生的计算

一个过程也就是一种模式,它描述了一个计算过程的局部演化方式,描述了这一计算过程中的每个步骤是怎样基于前面的步骤建立起来的。

计算过程的迭代与递归

  • 迭代计算过程,其状态可以用固定数目的状态变量描述
  • 递归计算过程,由一个推迟执行的运行链条刻画

考虑以下过程:

(define (fact-r n)
  (if (= n 1)
      1
      (* n (fact-r (- n 1)))))

(define (fact-i n)
  (fact-iter 1 1 n))

(define (fact-iter product counter max-count)
  (if (> counter max-count)
      product
      (fact-iter (* counter product)
                 (+ counter 1)
                 max-count)))

;; expand (fact-r 4)
(fact-r 4)
(* 4 (fact-r 3))
(* 4 (* 3 (fact-r 2)))
(* 4 (* 3 (* 2 (fact-r 1))))
(* 4 (* 3 (* 2 1)))
(* 4 (* 3 2))
(* 4 6)
24

;; expand (fact-i 4)
(fact-i 4)
(fact-iter  1 1 4)
(fact-iter  1 2 4)
(fact-iter  2 3 4)
(fact-iter  6 4 4)
(fact-iter 24 7 4)
24

其中fact-i迭代计算过程fact-r递归计算过程,它们在语法形式上都是递归过程

在常见的语言如C的大部分实现中,对于任何递归过程的解释,所消耗存储量与过程调用数目成正比,为了在这些语言里描述迭代过程,必须借助于特殊的循环结构,如forwhile

在Scheme中,对于迭代计算过程其总能在常量空间内完成,即使这一计算是用递归过程描述的。这一特性被称为尾递归

用高阶函数做抽象

过程也就是一类抽象,它们描述了一些对于数据的复合操作,但又不依赖于特定的数据。

能操作过程的过程被称为高阶过程,这些过程可以建立起进一步的抽象。

高阶过程的重要性在于使我们能够显式地用程序设计语言中的要素去描述这些抽象,使我们能像操作其他计算元素一样去操作它们。

带有最少限制的计算元素被称为具有第一级的状态,其部分权利包括:

  • 可以使用变量名
  • 可以提供给过程作为参数
  • 可以由过程作为结果返回
  • 可以包含在数据结构中

Lisp给了过程完全的第一级状态。

comments powered by Disqus