SICP (1)
记录学习的知识点。
程序设计的基本元素
- 基本表达形式,最简单的个体。
- 组合的方法,从简单的东西出发构造出复合的元素。
- 抽象的方法,为复合对象命名,并将他们当做单元去操作。
表达式
234 ,就是一个数,它也是一个表示数的表达式。
+ - * / ,这些运算符,属于表示过程的表达式,比如表示加的过程,表示减的过程。
将这两个组合,就形成了复合表达式。表示把加减乘除的过程应用到这些数上。
1 | (+ 112 342) |
命名
我有一个数字3.14,我给它取一个名字叫pi,这个名字就叫变量,它的值就是3.14。
scheme里用define方式完成:
1 | > (define pi 3.14) |
define它允许我们用一个简单的名字去引用一个组合运算的结果.
1 | > (define sum (+ 2 2)) |
环境
我们将3.14和pi这个名字用define定义好,后面又可以通过pi获取到3.14,那么解释器显然有存储能力,存储了pi和3.14的关系,这种存储就叫环境。
环境所扮演的角色就是确定名字(符号)的意义。
组合式求值
1 | (* (+ 2 2) |
这就是一个组合式,它是由若干个表达式组成的。
对它求值要做下面的事情:
- 对它的子表达式们进行求值,求值(+ 2 2)得到值4,求值(- 5 1)得到值4。
- 将最左边的运算符的过程应用到这两个值上,形成(* 4 4)。这两个值属于该表达式的参数。
为了实现对组合式的求值,我们必须先对组合式里的每一个元素做同样的求值过程。在性质上,这一求值过程是递归的。
用树状结构表示:
复合过程
1 | (define (square x) (* x x)) |
这个复合过程,表示将一个东西乘它自己。这个东西也给它取个名字叫x。
然后我们再将整个复合过程取一个名字叫square。
定义好后,就可以调用它了。
1 | > (square 10) |
我们还能将square当做基本构件去定义其他过程。
1 | > (define (sum-of-squares x y) |
代换模型
1 | (define (f a) |
说白了就是将形参换成实参,比如将a换成5。
1 | (f 5) |
提取出f的体。
1 | (sum-of-squares (+ a 1) (* a 2)) |
用实际的参数5替换其中的形式参数。
1 | (sum-of-squares (+ 5 1) (* 5 2)) |
现在运算符是sum-of-squares,两个运算对象分别是(+ 5 1)和(* 5 2)。
我们必须对运算符求值,得到那个过程。还需要对两个对象进行求值。
两个对象分别是5和10,用它们替换掉sum-of-squares过程中参数x和y
1 | (+ (square 6) (square 10)) |
square又可以进一步约分为:
1 | (+ (* 6 6) (* 10 10)) |
通过乘法又能将它们约分为:
1 | (+ 36 100) |
最后得到
1 | 136 |
应用序和正则序
正则序的求值方法和上一章不同,而是先不求出对象的值,等用到它们的之后再去做。
1 | (sum-of-squares (+ 5 1) (* 5 2)) |
然后才是约分:
1 | (+ (* 6 6) (* 10 10)) |
与正则序对应的是现在解释器里用的,”先求值参数而后应用”的方式,它被称为应用序求值。
条件表达式
至此我们定义出的过程表达能力还非常有限,还没有办法根据某种结果去做不同的操作。
这种结构称为分情况分析,检查一个数是正负或者0,根据不同的情况采取不同的动作。
Lisp中有着针对该情况的特殊形式,称为cond:
1 | (define (abs x) |
它表示如果 (> x 0)的条件为false,那就去求下一个(= x 0),如果还是false那就以此类推,知道发现那个条件为True的为止。
如果无法找到为True的条件,cond的值就没有定义。
还有一种写法是:
1 | (define (abs x) |
如果x小于0就返回-x,否则就返回x。
还有一种写法:
1 | (define (abs x) |
这里采用的是if形式。
逻辑复合运算符
and表达式:
1 | > (and 1 1) |
or表达式:
1 | > (or 1 1) |
not表达式:
如果
如果
1 | > (not #t) |
定义一个大于等于的过程:
1 | (define (>= x y) |