词汇表
问题
笔记
- 复合数据(Compound data):就像复合函数一样,我们增强了语言的表达能力,并提升了设计程序时所处的概念层次。
- 将数据粘合在一起(Glue data together):复合数据将数据粘合在一起,从而降低系统的复杂度。
- 数据抽象(Data abstraction):模块化数据能够将处理数据的代码部分与处理数据如何被表示的部分分离开来。
1 | // repesent, and deal with rational number |
2.1 数据抽象简介
词汇表
- 数据抽象(Data abstraction):与函数抽象相比,数据抽象隐藏了如何组合数据的细节,只暴露”是什么”。
问题
笔记
- 数据抽象的基本思想是:以这样的方式构建使用复合数据对象的程序,使其在”抽象数据”上进行操作。也就是说,我们的程序应该以一种不对数据做任何非执行当前任务所必需假设的方式使用数据。
2.1.1 示例:有理数的算术运算
词汇表
问题
笔记
- 一厢情愿(Wishful thinking):假设我们已经拥有某些尚未实现的东西,然后在此基础上继续构建。
- 抽象有理数算术运算的步骤:
- 我们基于数据抽象进行操作,所以先隐藏数据抽象的细节(一厢情愿)。
- 我们假设可以构造一个有理数,并能提取它的分子和分母。
1 | function make_rati(n, d) // make rational number which equal n / d |
1 | function add(a, b) { |
- 使用序对来实现假设的函数 make_rati、numer、denom。
1 | function pair(head, tail) // construct a pair with head and tail |
- 练习 2.1
1 | // handle positive and negative, we only change make_rati |
2.1.2 抽象屏障
词汇表
问题
笔记
- 总体而言,数据抽象的基本思想是:为每种类型的数据对象确定一组基本操作,所有该类型数据对象的操作都通过这些基本操作来表达,然后在操作数据时只使用这些操作。
水平线表示_抽象屏障_,将系统的不同”层次”隔离开来。这些屏障隐藏了其下方的实现细节。所有复杂数据都可以通过某种方式用原始数据来表示。如何表示数据会影响操作它的程序。但如果只修改实现层,不会影响构建在其上的程序。数据抽象方法使我们能够推迟这一决定,同时不失去在系统其他部分取得进展的能力。(例如,前端无需等待后端 API 完成,只要给出 API 文档(接口),前端就可以开始开发。)
- 练习 2.2
1 | // from top to bottom, using data-abstraction barriers to construct the system |
- 练习 2.3
1 | interface { |
2.1.3 数据意味着什么?
词汇表
- 数据(Data):由一组选择器和构造器定义,以及这些函数必须满足的特定条件,以构成有效的表示形式。
问题
笔记
- 只要能遵守规则并实现选择器和构造器,就可以将其用作数据。实现方式并不重要。
- 消息传递(Message passing):用函数表示数据,通过传递消息来获取特定的返回值。
- 消息传递实现序对
1 | // fulfill: z = pair(x, y) head(z) = x tail(z) = y |
- 练习 2.4
1 | function tail(z) { |
- 练习 2.5
1 | function pair(a, b) { |
- 练习 2.6
1 | const zero = f => x => x |
2.1.4 扩展练习:区间算术
词汇表
问题
笔记
- 练习 2.7
1 | function make_interval(x, y) { |
- 练习 2.8
1 | function sub_interval(x, y) { |
- 练习 2.9
1 | // proof: width A + width B = width C, where C is A + B (interval) |
- 练习 2.10
1 | function div_interval(x, y) { |
- 练习 2.11
1 | function mul_interval(x, y) { |
- 练习 2.12
1 | function make_center_percent(c, p) { |
- 练习 2.13
1 | // a * b -> pa * pb |
如果只看两个端点,有些问题会变得更难解决。但如果换个角度来看待数据,反而会变得更容易。