Java中,除了基本类型,其他类型都属于类/接口类型。从讨论数据抽象的角度看,基本类型是更适合的标的物,因为从Java虚拟机规范和Java虚拟机实现层面,基本类型有了有效的接口与实现分离。而类/接口类型的数据抽象,通常我们介绍封装、信息隐藏和类的接口等概念,它们说明Java类作为数据抽象,用户需要了解的是类的接口。
Scheme中,我们可以从基本类型构造新数据类型,换言之,我们可以赤裸裸地观察新数据类型的实现细节(不像Java,基本类型的实现细节由Java虚拟机实现厂商完成;程序员的自定义类型依靠的是类/接口这种定义方式,因而本部分的内容对我们学习《编程导论(Java)·第4章 数据抽象》,是一个很好的补充)。
Scheme所有从序对构造出来的数据被称为表结构(list-structured)数据。因而Scheme的数据分两种:基本类型和list。
Scheme构成新数据类型的方式,是将两个数据粘接在一起。现在我们就研究一下这个粘接剂502。
Pair
你将两个东西放在一起,并不能说明两者是什么关系。例如将《编程导论(Java)·1.2.5 案例:分数》中定义的分数/有理数的代码修改成如下。
public class X{ private int a; //分子numerator private int b = 1; //分母denominator public int getA(){return a;} public int getB(){return b;} }
你如何知道X是分数还是复数或什么别的东西呢?X的类型含义,由它的操作接口(分数的加法还是复数的加法)来刻画。
Scheme定义新类型的通用结构称为pair(对,序对——裘的翻译,我不经意地想到序偶),这里不关心数据类型的实际意义和它的接口,而是单纯地看看如何“二生三,三生万物”。
和pair相关的3个通用函数。
l 构造子(constructors,构造函数) cons,将两个东西放在一起。
(define x (cons 1 2))
l 选择子(selectors,选择函数) car和cdr,可以将car看成getOne,cdr看成getTwo。
(car x)
→1
(cdr x)
→2
(SICP介绍,The name cons stands for ``construct.‘‘ The names car and cdr derivefrom the original implementation of Lisp on the IBM 704. Car stands for``Contents of Address part of Register‘‘ and cdr (pronounced ``could-er‘‘)stands
for ``Contents of Decrement part of Register.‘‘)
可以用指针来了解序对(cons 1 2)。这里有3个指针,x或(cons1 2)整体作为一个指针,指向一个两单元的盒子;两单元中前者保存指针car,后者为cdr。
目前car指向的空间保存一个数字1。如果car或/和cdr指向的空间,保存一个指向序对的指针,由此就可以形成更复杂的数据整体(属于某一数据类型,形成某种数据结构)。
闭包(closure)
来自于抽象代数的概念,闭包(closure)用于说明某个集合的性质(如同SICP,我们也不考虑它的另外一个含义——带有数据的行为)。
“道生一,一生二,二生三,三生万物”。这里有一个前提,所有衍生的东西,都属于一个集合。如人生出的孩子,也是人,他们可以继续生孩子;整数相加的结果还是整数。所以,闭包(closure)说明了一个集合满足一个条件:对集合元素的操作,其结果属于该集合(因而可以再次对它进行操作)。
具有闭包性质的集合,具有“三生万物”的强大能力。序对cons作为通用构造块,可以演化出这种构造方式下最适合、好用而且复杂的各种数据类型——例如描述《数据结构》中各种结构的数据类型。
序列
序列(sequence)是一组有序数据的集合,如{1 2 3 4}。在Java中用数组或链表来描述/保存序列。
假设每个序对的car指向的空间(其实可以视为 本地) 保存一个数字,而cdr保存一个序对的指针,这样,每个序对如同一个单向链表的结点。注意:最后一个序对中包含了一个表明序列结束的nil(null的拉丁语)。
(cons 1 (cons 2 (cons 3 (cons 4 nil))))
这个简单的复合数据/数据结构很常用,Scheme提供了一个便宜操作符list,使程序员更方便地表示上面的表达式。
(list 1 2 3 4)
→(1 2 3 4)
(list 1 (list 2 3 4))
→(1 (2 3 4) )
(cons 1 (list 2 3 4))
→(1 2 3 4)
(cons (list 1 2) (list 34))
→( (1 2) 3 4)
(list (list 1 2) (list 34)) ; 用树来解释本表达式
→( (1 2) (3 4) )
值得注意的是,数据类型和数据结构的有趣关系。
(define x (cons 12)),我们不知道x是什么数据类型;
(define x (list 12)),或(define x (cons1 (cons 2 nil)))
我们知道x是一个list。
符号数据
假设(define x (cons 1 2))定义的,是一个分数1/2(不是复数),作为一般的应用,数学家们希望使用代数符号,例如(define x (cons a b))表示一个分数a/b。这里a、b是表示任意数的符号。
下面的例子中,虽然定义了分数a/b,但是a、b不是表示任意数的符号。
(define a 1 )
(define b 2 )
(define x (cons a b))
Scheme提供了前缀引号,例如’a表示这里的a是一个符号。
(list ‘a ‘b ‘c)
→( a b c )
下面再学习:粘接之后,我们要干什么。如(1)对于分数或复数,如何由它的操作接口刻画其类型;
(2)如何操作和应用list...
版权声明:本文为博主原创文章,未经博主允许不得转载。