全部学习汇总: https://github.com/GreyZhang/g_SICP
我们自然是可以利用一堆的最基础的运算来表达我们的处理的对象,但是这样的话就有很多限制点。首先,我们没法脱离基础运算来思考一个算法实际本身,或者说进入不到更加合理的表达层级。另外一点,解决问题的过程会更加繁复。因此,很多编程语言其实都提供把一段代码绑定成一个函数的方法。这里的函数,procedures,其实就是处理的方式。
前面的学习内容中,采用了定义函数的抽象方式来让思考更加高层次一些。处理的方式都是定义函数,传入数据。相比直接底层的数据操作来说,这个已经很有改进点了。但是我们在解决问题的时候遇到的局面可能并不仅仅是处理数据,有时候我们需要处理的恰恰是处理方法本身。这就引入了接下来的学习主题:高阶抽象。那么什么是高阶函数呢?简单说就是能够处理函数的函数。
这里给出了三个计算例子,其实每一个都是类似的实现模式。
从代码实现的角度上来说,都是满足上面的这个模板的。
这种表述方式,可以让人联想到数学表述里面的级数。这个级数的表达,其实是很多可能性的组合,因为没有给出具体的公式。但是,通过这种表发方式把类似的内容进行了统一化的表达。
类似的,软件之中把这个f(x)抽象出来,作为一个可处理的对象就可以有上面的这种设计模式。而这样的设计,固化了处理的模式,只需要去完成我们需要判断的小细节。
这一章节的后面有一个值得去做一下题目,这个。前面的处理模板其实是一个树递归的过程,这种处理在理解上容易但是可能会导致算法的效率以及存储的占用。如果改成一个迭代的模式呢?上面给出了框架,需要我们自己填补。而我的填补如下:
(define (sum term a next b)
(define (iter a result)
(if (> a b)
result
(iter (next a) (+ result (term a)))))
(iter a 0))
这是另一个可以做一下的题目,前面的表达方式是级数,是求和。如何实现一个求乘积的功能呢?我的设计如下:
(define (product term a next b)
(if (> a b)
1
(* (term a)
(product term (next a) next b))))
(define (factorial n)
(product num-term 1 next-num n))
(define (num-term x)
x)
(define (next-num x)
(+ x 1))
这是计算的结果。
设计的这个模式,自然也是一个递归的过程。接下来尝试改成一个迭代的版本。
(define (product term a next b)
(define (iter a result)
(if (> a b)
result
(iter (next a) (* result (term a)))))
(iter a 1))
做几个简单的测试如下:
递归的版本我没敢计算最后一个,相比之下,迭代的版本可以测试一下,因为这个计算的速度要快得多。
(define (pi-term n)
(if (odd? n)
(/ (+ n 1) (+ n 2))
(/ (+ n 2) (+ n 1))))
(define (p-pi n)
(* 4.0 (product pi-term 1 next-num n)))
借由上面的公式做出来的一个pi的计算函数,测试的效果如下:
我印象中之前还见过拉马努金的一些公式,也是跟pi有关的。或许,哪天有空了可以研究下拉马努金的研究成果,用计算机证实一下。
再看这个题目,其实这个做起来应该很容易。直接拿前面的代码改造即可。
(define (accumulate combiner null-value term a next b)
(define (iter a result)
(if (> a b)
result
(iter (next a) (combiner result (term a)))))
(iter a null-value))
(define (fac n)
(accumulate * 1 x-num 1 next-num n))
(define (x-num x) x)
(define (next-num x) (+ x 1))
这是我的实现,接下来测试:
由于算法是迭代处理的,处理的速度其实还是很快的。
总体说来,这个小节所介绍的内容之前我基本上还是熟悉的。按照这个模式用过,最典型的两种方式:1,python之中的switch实现;2,C语言中的回调函数使用,典型的莫过于快速排序的功能实现中提供比较函数。不过,在实际的工程实践中,类似的想法用的的确是不多,设计的软件很多时候都是欠缺打磨的,这算是以后需要改进的地方。