抽象数据的多重表示

  1. 对于一个数据对象可能存在多种有用的表示形式,而且也可能希望所设计的系统能处 理多种表示形式;
  2. 除了需要将表示与使用相隔离的数据抽象屏障之外,还需要有抽象屏障去隔离互不相 同的设计选择,以便允许不同的设计选择在同一个程序里共存;
  3. 进一步说,由于大型程序常常是通过组合起一些现存模块构造起来的,而这些模块又 是独立设计的,我们也需要一些方法,使程序员可能逐步地将许多模块结合成一个大 型系统,而不必去重新设计或者重新实现这些模块;
  4. 本节构造通用型过程(可以在不止一种数据表示上操作的过程)所采用的主要技术, 是让它们在带有 类型标志 的数据对象上操作(即让这些数据对象包含着它们应该 如何被处理的明确信息);
  5. 本节还讨论 数据导向 的程序设计,这是一种用于构造采用了通用型操作的系统的 有力而且方便的技术;

复数的表示

  1. 复数表示为有序对的两种可能表示方式:直角坐标形式(实部和虚部)以及极坐标 形似(模和幅角);
  2. 复数的两种不同表示方式,分别适合不同的运算(直角坐标适合加减,极坐标适合 乘除);
  3. 从编写使用复数的程序的开发人员角度看,数据抽象原理的建议是所有复数操作都 应该可以使用,无论计算机所用的具体表示形式是什么;

带标帜数据

  1. 最小允诺原则:在实现程序时,由选择函数和构造函数形成抽象屏障,使我们可以 把为自己所用的数据对象选择具体表示形式的事情尽量向后推,而且还能保持系统 设计的最大灵活性;
  2. 本节例子的最终形态将数据对象从一个层次传到另一个层次的过程中,剥去和加上 标志的规范方式可以成为一种重要的组织策略;

数据导向的程序设计和可加性

  1. 检查一个数据项的类型,并据此去调用某个适当过程成为基于类型的分派,这在系 统设计中是一种获得模块性的强有力策略;
  2. 数据导向 的程序设计技术就是一种使程序能直接利用类似 类型-操作 二维表 格工作的程序设计技术,表格中 作为元素的过程 针对作为参数的每个类型实现 每一个操作,能够将系统设计进一步模块化;
  3. 章节 2.4.2 让每个操作管理自己的分派,实际上就是把 2.4.3 中的二维表格分解 为一行一行,让每个通用型过程表示表格中的一行;
  4. 另一种实现策略是将这一表格按列进行分解,采用“智能数据对象”(其实就是将数 据对象用过程来表示,关键词 dispatch)让它们基于操作名完成所需的分派工作, 这种策略就是 消息传递 (将数据对象设想为一个实体,以“消息”的方式接收到 所需操作的名字);
  5. 消息传递是一种有价值的技术,第三章将会详细讨论并用于构造模拟程序。

练习 2.73-2.76

2.73

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
;; a

;; 数字和符号是 scheme 的基本元素,有语言内置的过程可以识别和区分;而且区分之后
;; 直接返回数值,并不需要过程计算(如果一定要全部都使用表格分发也行,但改动较多
;; 且无必要);

;; b & c

;;其余过程和 3.3.2 实例及乘幂求导练习一致
(define (addend s) (car s))

(define (augend s)
  (if (null? (cdr s))
      0
      (cons '+ (cdr s))))

(define (multiplier p) (car p))

(define (multiplicand p)
  (if (null? (cdr p))
      1
      (cons '* (cdr p))))

(define (exponent x)
  (cadr x))

(define (base x)
  (car x))

(define (deriv-product operands var)
  (make-sum
   (make-product (multiplier operands)
		 (deriv (multiplicand operands) var))
   (make-product (deriv (multiplier operands) var)
		 (multiplicand operands))))

(define (deriv-sum operands var)
  (make-sum (deriv (addend operands) var)
	    (deriv (augend operands) var)))

(define (deriv-exponentiation operands var)
  (make-product (exponent operands)
		(make-product
		 (make-exponentiation
		  (base operands)
		  (make-sum (exponent operands) (- 1)))
		 (deriv (base operands) var))))

;; install

(define (install-deriv-package)
  (put 'deriv '* deriv-product)
  (put 'deriv '+ deriv-sum)
  (put 'deriv '** deriv-exponentiation))

;; d

(define (install-deriv-package)
  (put '* 'deriv deriv-product)
  (put '+ 'deriv deriv-sum)
  (put '** 'deriv deriv-exponentiation))

2.74

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
;; 以前自己的解答,就不翻译了
;; a

(define (get-record name file)
  ((get 'get-record (tag file)) name (contents file)))

;; file (cons tag (cons name record) ... ) or some other structures
;; (put 'get-record the-exact-tag the-exact-get-record-procedure)


;; b

(define (get-salary name file)
  (let ((record (get-record name file)))
    ((get 'get-salary (tag record)) (contents record))))

;; record (cons tag salary-content ...) or some other structures
;; put behaves like a


;; c

(define (find-employee-record name file-list)
  (define (iter file-list result)
    (cond ((null? file-list) result)
	  ((null? (get-record name (car file-list)))
	   (iter (cdr file-list) result))
	  (else (iter (cdr file-list) (cons (get-record name (car file-list)) results)))))
  (iter file-list '()))


;; d

;; if possible, give new and uniq#+HUGO_TAGS to this file and its certain records
;; with the procedure 'put' and n#+HUGO_TAGS, install the corresponding procedures

2.75

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
(define (make-from-mag-ang x y)
  (define (dispatch op)
    (cond ((eq? op 'magnitude) x)
	  ((eq? op 'angle) y)
	  ((eq? op 'real-part)
	   (* x (cos y)))
	  ((eq? op 'imag-part)
	   (* x (sin y)))
	  (else
	   (error "Unknown op -- MAKE-FROM-MAG-ANG" op))))
  dispatch)

2.76

1
2
3
4
5
6
;; 带有显式分派的通用型操作在加入一个新类型或者新操作时对代码的改动较大,带来不
;; 便,容易引进错误

;; 消息传递更适合用于需要经常加入新的数据对象类型的系统;

;; 数据导向更适合用于需要经常加入新的操作的系统(存疑,经常加入新的操作的话,使用消息传递风格并不会更麻烦);