SICP 习题 (2.1) 解题总结

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的总结了,关键还是理解“序对”这个概念。

时间: 2024-12-18 00:22:15

SICP 习题 (2.1) 解题总结的相关文章

SICP 习题 (2.30)解题总结 : Square-Tree

SICP 习题 2.30 要求我们完成一个叫square-tree的过程,其作用和之前的square过程差不多,square过程是针对简单列表的,将列表中的所有元素求平方,然后返回新的平方数列表.不过square不能对嵌套列表进行处理,如果列表中还包含列表的话会报错. 题目要求我们实现一个square-tree的过程,当输入的列表包含另一个列表时可以对嵌套的列表进行处理,生成所有列表元素的平方数. 这个和之前几道题差不多,都是对树状列表的遍历和处理.题目还要求我们用两种方式实现,一种使用map,

SICP 习题 (1.46)解题总结

SICP 习题 1.46 要求我们写一个过程iterative-improve,它以两个过程为参数,其中一个参数用来检测猜测是否足够好,另一个参数用来改进猜测.过程iterative-improve应该返回另一个过程,所返回的过程接收一个参数作为初始猜测,然后不断改进猜测直到结果足够好.题目还要求我们使用iterative-improve重写1.1.7的sqrt过程和1.3.3节的fixed-point过程. 因为涉及到高阶函数,所以整个题目理解起来有一点点费劲.不过这道题作为第一章的收官题确实

SICP 习题 (1.45)解题总结

SICP 习题 1.45是对前面很多关于不动点的习题的总结. 题目回顾了我们之前在1.3.3节使用的不动点寻找方法,当寻找y -> x/y 的不动点的时候,这个变换本身不收敛,需要做一次平均阻尼才可以. 对于y -> x/(y^2)这个变换也可以通过一次平均阻尼使它变得收敛. 不过一次平均阻尼对于四次方程是不够的,就是说,对y -> x/(y^3)这样的变换,一次平均阻尼不足以使它收敛,需要做两次平均阻尼才行. 题目遵从一直以来的抽象原则,要求我们去多做几次测试,找出 y -> x

SICP 习题 (2.10)解题总结: 区间除法中除于零的问题

SICP 习题 2.10 要求我们处理区间除法运算中除于零的问题. 题中讲到一个专业程序员Ben Bitdiddle看了Alyssa的工作后提出了除于零的问题,大家留意一下这个叫Ben的人,后面会不断出现这个人,只要是这个人提到的事情一般是对的,他的角色定位是个计算机牛人,不过是办公室经常能看到的那种牛人,后面还有更牛的. 对于区间运算的除于零的问题,处理起来也比较简单,只需要判断除数是不是为零,除数为零就报错.对于一个区间来讲,所谓为零就是这个区间横跨0,再直接一点讲就是起点是负数,终点是正数

SICP 习题 (2.22)解题总结: 迭代过程中的列表处理

SICP 习题 2.22是习题2.21的后续题目,题目中讲到叫Louis Reasoner的人想重写suqare-list过程,希望使用迭代计算过程,而不是递归计算过程,有关迭代计算过程和递归计算过程,如果你没什么印象了,请翻回习题1.9 的解题总结看看. 那个叫Louis Reasoner的人写的迭代版的suqre-list是这样的: (define (square-list-revert items) (define (iter things answer) (if (null? thing

SICP 习题 (2.2) 解题总结

SICP 习题 2.2要求我们使用这一节的数据抽象方法定义几何里"点"的概念,还要定义"线段"的概念,最后还要求我们定义midpoint-segment过程,这个过程根据参数中的线段进行计算,返回该线段的中点. 题目还给出了一个print-point过程,用于输出一个点,代码如下: (define (print-piont p) (newline) (display "(") (display (point-x p)) (display &quo

SICP 习题 (1.36)解题总结

SICP 习题 1.36 要求我们修改fixed-point函数,使它能够打印出计算中产生的近似值序列,使用练习1.22展示的newline和display方法.而后通过找出变换x => log (1000)/log(x)的不动点的方式确定x^x=1000的一个根(书中还提示你使用Scheme的基本过程log,用于计算自然对数值).然后比较一下使用平均阻尼和不用平均阻尼的计算步数.要注意的是不能使用1作为初始猜测去启动fixed-point,因为log(1)=0,会导致0除数错误. 从题目来看,

SICP 习题 (1.38)解题总结

SICP 习题1.38 紧跟着习题1.37的方向,要求我们用习题1.37中定义的cont-frac过程计算数学家欧拉大师在论文De Fractionibus Continuis 中提到的e-2的连分式.说实话,我不知道论文De Franctionibus Continuis讲的是什么,我甚至不知道论文的题目是什么意思.不过,这一切都不能阻止我这个数学盲去解答这道SICP习题. 仔细阅读题目,我们可以发现题目要求我们计算的是下面这样的无穷连分式: 其中N永远等于1, D等于1 ,  2 , 1 ,

SICP 习题 (1.39)解题总结

SICP 习题1.39沿着习题1.37, 1.38的方向继续前行,要求我们根据德国数学家J.H.Lambert的公式定义tan-cf过程,用于计算正切函数的近似值. J.H.Lambert的公式如下: 可以发现,这个和之前的无穷连分式是一样一样的,所不同的就是N是一个变量,不是固定数值. 不过这个已经难不倒我们啦,可以从公式中发现,除了第一个N是x,其它的N都是x平方, D对应的数值是1,3,5,就是所有奇数,以数字n为下标的话可以通过((n * 2)-1) 得到. 最后直接定义以下过程搞定:

SICP 习题 (1.37)解题总结

SICP 习题 1.37是一条很长的题目,主要讲的是无穷连分式.无穷连分式对我来说又是一个陌生的概念,于是又去百度了一番,发现无穷连分式也是一个很有意思的话题,涉及到无理数的表达.不过我建议大家还是暂时不要深入思考它的数学含义,一旦开始思考可能你又会跳进数学的深渊中不可自拔. 无穷连分式的形式如下: 就像书中说到的,作为无穷连分式的一个特殊例子,如果N和D都为1的话,f= 1/ φ, 这点可以结合我们之前对黄金分割率的计算证明,这里就不多说了,而且,如果你不能从数学上理解它也无所谓,不影响我们做