Scheme 4 Javaer-4.Pair、car和cdr

来源:互联网 发布:音频分析软件 编辑:程序博客网 时间:2024/06/05 11:14

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...

0 0