将抽象作为克服复杂性的一种技术
组合式
(+ 1 1)
解释器
将组合式的各个部分求值,包括运算符和各个参数
(过程应用的)代换模型(Substitutions)
把复杂组合式逐步分解成每个部分求值的结果,并非解释器的实际处理方式替换模型
正则序求值
先求解操作符,最后求解后求解值。在书中涉及平方函数的调用,使得被平方的表达式被处理两次而非表达式的结果值进行平方。(square (+1 1))
被解释成(* (+1 1) (+ 1 1))
而非(* 2 2)
应用序求值
先求参数,再求操作符
注
:在能够通过替换模拟的得到合法值的过程应用中,两种求值顺序会获得相同的结果。
谓词
指哪些返回真或假的过程,或求得真或假的值的表达式
(define (abs x)
(cond ((< x 0) (-x))
(else x)))
(define (abs x)
(cond ((< x 0) -x)
((= x 0) 0)
((> x 0) x)))
(if )
(and ... );阻断
(or ... );阻断
(not )
说明性
数学定义,描述是什么
行动性
计算机科学,描述怎么做
过程抽象
隐藏一些细节,在使用时不需要弄清它是如何实现的
下文中good-enough?的判断就抽象了一个过程,不论是什么,只要能完成任务就行。
(define (sqrt x)
(sqrt-iter 1 x))
(define (sqrt-iter guess x)
(if (good-enough? guess x)
guess
(sqrt-iter (improve guess x) x))))
局部名
函数参数的名字不会与调用他的地方的名字冲突。这么想lisp的宏定义会造成这样的问题,所以使用了临时变量名之类的机制。
高阶过程
把过程当参数传递
被约束的
做用域
声明这个形参的过程的体就是作用域
(define (sqrt x)
(sqrt-iter 1.0 x))
(define (sqrt-iter guess x )
(if (good-enough? guess x)
guess
(sqrt-iter (improve guss x) x)))
-> ;将sqrt-iter包进sqrt的声明里
(define (sqrt x)
(define (sqrt-iter guess x )
(if (good-enough? guess x)
guess
(sqrt-iter (improve guss x) x)))
(sqrt-iter 1.0 x))
-> ;把x作为内部变量使用
(define (sqrt x)
(define (sqrt-iter guess)
(if (good-enough? guess)
guess
(sqrt-iter (improve guss))))
(sqrt-iter 1.0))
值得定义哪些过程
评估棋步(路线和范围)的价值
对执行一个过程的效果做出预期
走棋的后果
通常提到递归模式
时,指过程直接或间接地引用了过程本身。
CS公开课中提到的例子
尾递归和线性递归都把一个活交给另一个人,但要求返回的东西不同
尾递归可以要求中间人一个人把他的答案还给第一个,而线性递归必须把结果还给前一个人(因为他还要做自己的计算)
存在递归模式,但是是迭代的计算过程,比如尾递归。
区别的方式之一是掐断任意过程时是否有参数之外的变量影响计算结果,如下的计算过程,其结果取决于函数之外的x * factorial(x),而非参数(- x 1)。
(define (factorial x)
(if (= x 1)
x
(* x (factorial (- x 1))))
考虑空间复杂度的时候,我因为树形递归太乱而愣了一下,没理解它等于O(n)的原因。
看视频的时候跟着老师的手一个一个记,因为一条树走完往回的时候其实就不用记那边的事了,记新的路线就行。相当于施放出一定旧空间记新内容,所以没有增加。
通过xn=(x2)n/2,可以实现迭代化的计算。不过一开始对于计算不清晰,绕了很多思路。最后把步骤一行行写纸上,归纳起来就清晰多了。
x | a | n |
---|---|---|
3 | 1 | 7 |
3 | 3 | 6 |
9 | 3 | 3 |
9 | 27 | 2 |
81 | 27 | 1 |
81 | 27*81 | 0 |
一开始不理解n是奇数时,a的迭代方式为什么是a = a * x,x一直平方不会错吗?但根据计算步骤归纳起来就基本不担心了。
用过程作为参数或返回值
匿名函数
除了没有名字,跟define函数一模一样
(lambda (
(let ((1>
(2>
.
.
.
)
函数内用define可以起到相同效果,只是习惯上函数内只用define定义过程
(define (f x y)
(define a (+ 1 (* x y))
(define b (- 1 y)
)
;=
(define (f x y)
(let ((a (+ 1 (* x y)))
(b (- 1 y)))
))
先define了(search f a b)
根据(f a) (f b)的值一个大于0一个小于0,逐步求(average a b)来逼近(f x)=0。
然后考虑f本身的特殊性
(f a)和(f b)不一定能确定谁大于0,谁小于0,甚至可能都在0的同一侧。因此加一层包装,确保传给search的a b可以得到f x在0的两侧,同时也分配(f x)小于0的参数到a,大于0的到b。
f(x) = x
也可以用于求平方根y*y = x -> y = x/y
,变换后的f(y)=y
其中f(y)包含了x,并非无视x进行计算
(define (sqrt x)
(fixed-point (lambda (y) (average y (/ x y)))
1.0)
带有最少限制的元素被称为具有第一级的状态,他们具有如下权利或者特权
lisp给了过程第一级状态
DataLayers Something like segments, vectors, numbers. If we get X of
the start point of segment L. It can be represented as(xcod (pos-s L))
. Not(car (car L))
. When the quest changes into get end point
of L. We can easy find pos-s want be change.Instend of finding what
car means in the other one.
更正
书中对数据抽象的优点的例子是数据表示形式改变的情况,如segment L的起点和终点形式改变时(如从两点改为(起点,斜率,长度)。不需要修改所有涉及线段的代码,只要pos-s函数仍然能返回正确的起点即可。
这样做可以让线段数据表示形式的问题被隐藏起来,至少在应用线段这个数据时不需要考虑用什么方式表示线段更好。
(define x (cons 1 2))
(car x) // 1
(cdr x) //2
(口口),每个空位可以存一个对象,可以是序对。列表是序对的延伸,头是值,尾指向下一个,直到尾是Nil。
适当的选择函数
和`构造函数
模糊了过程和数据的边界
(define (cons x y)
(define (dispatch m) ;lambda(m) is also right
(cond ((= m 0) x)
((= m 1) 1)
(else (error "argument not 0 or 1"))))
dispatch)
(define (car z) (z 0))
(define (cdr z) (z 1))
(list a b c d e)
(define (f x y . z) )
中 .
号表示剩下的实参都放到.
后的形参里
(f 1 2 3 4 5 6 7) ; x 1,y 2 z (3 4 5 6 7)
(define (g . w) )
(g 1 2 3 4 5 6) ; w ( 1 2 3 4 5 6)