SICP 习题 2.1 要求我们做一个可以正确处理正数和负数的make-rat过程,用于生成一个有理数。条件是分母必须是正数。
完成这道题本身比较简单,就是简单修改一下书中的make-rat过程就可以了。
书中原本的make-rat过程如下:
(define (make-rat n d) (cons n d))
可以发现,原来的make-rat就是简单地将n和d组成一个序对,然后返回这个序对,并没有对分子和分母进行判断。
我们要做的就是修改make-rat过程,判断一下分母d是不是小于0,如果分母小于0,则同时求分子和分母的相反数,用cons串起来就好了,代码如下:
(define (make-rat n d) (if (< d 0) (cons (- n) (- d)) (cons n d)))
不过我们做题目不能只是以完成题目为目的,我们做题目是希望更好地理解书中讲述的内容。
SICP一书在这个小节主要讲得就是数据抽象,让我们了解复杂数据的组织、保存和获取的方法。其次是让大家了解,相同的数据可以使用不同的方式来保存。
这里面同学们一般会有两个疑问:
第一个疑问是为什么需要自己处理有理数,Scheme中不是可以处理有理数吗?
第二个疑问就是为什么要使用cons来将分子和分母连接起序对?
有关第一个疑问,我们需要了解SICP一书的主旨。SICP这本书是向我们讲解计算机程序的结构和解析方法,是希望我们可以通过这本书的学习了解开发一门语言的整个过程。所以说,虽然Scheme已经可以支持有理数,作者还是希望我们通过Scheme去实现自己的有理数模块。打个比方,就好像你和一个铁匠学习铁器技艺,你师父给你一个铁锤和一块生铁,要你做个铁锤出来,并不是说你师父没有铁锤用,你师父有个锤子!他只是希望你学会如何使用铁锤把一块生铁做成铁锤。
这个观念在整本书的阅读过程中都要保持清晰,后面我们还会面对很多这样的需求,比如用Scheme做一个Scheme出来。。。。
有关第二个疑问,就是为什要使用cons,这个说实在话,在Lisp中,在Scheme中,用于组织数据的方法并不多,甚至可以说只有cons一种。
SICP一书在后面的章节中也介绍了更多的数据组织方法,包括列表,表,树等。不过,在Scheme中,以上这些数据结构最终还是由cons完成的。就是说,用cons组成的序对是Scheme里地原始数据结构,其它的数据结构都是由序对这个数据结构组成的。
所以,我们需要好好理解序对的作用。
正像书中说的,序对其实很简单,就是使用cons连接起来的两个数据,第一个数据可以通过car指令获得,第二个数据可以通过cdr指令获得。
这里要注意,cons连接的数据可以是基本数据,也可以是另一个序对。
有关car和cdr的这两个指令名称的来源,可以看看书中的注释68,看完你就知道,原来Lisp的历史是如此的悠久。另外就是有关这两个指令的读法,car就像我们读英文“汽车 car”那样读,cdr读起来比较麻烦,因为它单词里没有元音,大概的读音是“酷的”这样,如果希望了解cdr的准确读法,可以去看看MIT的原版SICP的视频。
虽然序对很简单,但是它的作用却很大。
如果我们把一个单一的数据比作是一个点的话,cons命令就好像是一条线,可以将两个点连接起来的线。
只要我们有了连线这样的工具,我们就可以将不同的点连接起来,连接成不同的结构,比如我们可以连出一个“树型结构”,或者是连出一个“队列结构”。
这也是抽象的力量,对不同数据结构的构成进行抽象,我们会发现构成不同数据结构的根本元素就是“点”和“线”,在Lisp中,基础数据就是“点”,cons就是“线”。所谓“序对”,就是用一条线连接起来的两个点。
以上就是SICP 2.1的总结了,关键还是理解“序对”这个概念。