计算机程序的构造和解释(SICP) Lec2b 复合数据 的个人心得(未完成)

在设计一个复杂的计算机系统的时候,如果是要处理分数之间的计算,要如何实现呢?

文中给出了一种假设法

计算机程序的构造和解释(SICP) Lec2b 复合数据 的个人心得(未完成)
假设有一个函数MAKE-RAT(第一行),用于记录这个分数,N和D变量表示分子和分母,使用愿望思维,不必关心他是如何实现的,你就当他已经实现了
如何第二行和第三行的NUMER和DENOM分别是MAKE-RAT下的方法,用于取出MAKE-RAT表示的分子和分母
所以这么做的好处是什么呢?
计算机程序的构造和解释(SICP) Lec2b 复合数据 的个人心得(未完成)
比如我们要使用XY(XY都是分数),我们就可以使用MAKE-RAT用分子乘分子,分母乘分母
(NUMER X)(NUMER Y))
(*(DENOM X)(DENOM Y))

这么做有什么好处吗?

试问如果不用这种表示方式,每个分子和分母都用不同的变量名来命名我们会得到
计算机程序的构造和解释(SICP) Lec2b 复合数据 的个人心得(未完成)
那只要进行一个分数乘法就需要四个变量来记录,这对于我们的使用是非常繁琐不必要的。如果这样的捆绑数据20个为一组?那还咋用

好的,那么现在,我们给MAKE-RAT命名为有理数的构造函数

NUMER 和 DENOM 为选择函数

现在使用这两种方式进行编程
计算机程序的构造和解释(SICP) Lec2b 复合数据 的个人心得(未完成)
MAKE-RAT定义一个A和B再使用+RAT来计算得出的结果,我们会发现得到的不是想要的3/4而是6/8
因为+RAT只是把分子乘分母的和(1x4+1x2) 和分母乘分母(2x4)拼接在一起并没有进行约分,那么可以进行改进,改进后为
计算机程序的构造和解释(SICP) Lec2b 复合数据 的个人心得(未完成)
在MAKE-RAT中加入一个过程,在构造一个分数的时候自动求出公约数,然后用分子和分母去除以这个公约数,得到的就会是约分后的结果(框起来的这部分就是调用了MAKE-RAT)
计算机程序的构造和解释(SICP) Lec2b 复合数据 的个人心得(未完成)
OK那到现在,我们就完成了一个完整的有理数计算系统。我们有+RAT,
*RAT,-RAT等方法,我们是使用了序对来实现了数据的表示(也就是分子和分母的绑定数据),在中间有一个抽象层,就是构造函数和选择函数(看下图)
计算机程序的构造和解释(SICP) Lec2b 复合数据 的个人心得(未完成)
这就是数据抽象的形式,在编程的时候不需要关心构造函数如何实现,也不需要关心数据,只是计算方法和构造函数之间的编程。
通过抽象层将数据对象的表示和使用分离开来
那么数据抽象有什么意义呢?我们不使用数据抽象的方式,也可以达成有理数的计算
计算机程序的构造和解释(SICP) Lec2b 复合数据 的个人心得(未完成)
图中直接使用了car和cdr表示了分子和分母,省去了中间繁琐的抽象层,但是这么做相比上一个方式有什么区别呢?很明显,我们没有一个值去表示分子和分母了。在程序中需要有一个名字去控制一个值,这样就可以实现解耦以及更高的灵活性。如果是使用上图方法定义的话,现在是实现了+RAT,如果还有x RAT -RAT。那就得重复的写这个约分的步骤。接下来我们继续展示另外一种化简的方式
计算机程序的构造和解释(SICP) Lec2b 复合数据 的个人心得(未完成)
我们改变了选择函数NUMBER和DENOM。使它再被调用的时候进行简化,而不是有理数在构造的时候。这种方式和上一种方式各有千秋,如果我们的系统经常构造有理数,那么在创建的时候最好不要简化,可以提升性能,但是如果我们经常需要使用一个有理数的时候,那么在构建初期就简化可以一劳永逸。

小结

在构建一个系统的时候,有时找不到一个合适的解决方式,最高性能的方式就是在使用之前不去决定采取那种方式,那么采取数据抽象就是一个很好的方式,你只需要按照愿望思维编程而并不需要关心他如何实现。在你真正需要使用的时候再采取处理方式(就好像java中的接口,不需要管如何实现,你就当他已经实现了。到了真正要使用的时候,再去完善实现类。)