Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
81 lines (55 sloc) 3.16 KB

复数系统

Polar Rectangular
real-part real-part-polar real-part-rectangular
img-part img-part-polar img-part-rectangular
magnitude magnitude-polar magnitude-rectangular
angle angle-polar angle-rectangular

这道题目算是对这2.4小节的一个总结。下面我一一分析这三种方式的利与弊:

显示分派

很明显,这种方式无论是新增操作还是新增类型都是不好的,都需要修改所有的代码。

数据导向

主要特点:

  1. 相当于把表格横向切分,每行实现为一个“智能操作”
  2. 把操作定义得足够强大(是能理解类型的智能操作),它们能根据被处理的数据的类型决定采用的具体操作

这种情况就是把一种数据类型的所有操作封装到一个package中。

  • 如果新增类型,只需再增加一个package即可,原有代码不需要修改,
  • 如果新增操作,也不需要修改之前的代码,只需要在增加相应的分发函数即可(在另一个 package 中)。

消息传递

主要特点:

  1. 把表格纵向切分
  2. 定义足够聪明的“智能数据对象”,这种对象能根据送来的操作 名决定自己要做的工作
  3. 面向对象技术里定义的就是这种对象,操作与对象绑定在一起

关于第三点比较重要,看下面这个例子加深理解:

(define (cons x y) 
  (lambda (m)
    (cond ((= m 0) x) ((= m 1) y)
    (else (error "Argument not 0 or 1 -- CONS" m)))))

(define (car z) (z 0))

(define (cdr z) (z 1))

cons 是生成数据对象的过程,送给对象的消息是 0 和 1,要求它给出自己的 car 和 cdr 部分。

这种情况就是把数据对象看作一个分发过程(dispatch),根据实际传入的过程名来确定将要调用的过程。

  • 如果新增类型,只需再增加一个分发过程,原有代码不需要修改
  • 如果新增操作,则需要修改每个分发过程,把新增的操作添加上

总结本题

本题要解决的其实是表达式问题,即:

如何在不修改之前代码的前提下,让以有操作支持新类型已有类型支持新操作

消息传递的方式有效的解决了这个问题。 关于表达式问题,更多可参考:

数据导向的方式比消息传递的方式有一个好处,那就是

数据导向方式的操作可以有多个类型的参数(这也就是注解111所说的),而消息传递的只能有一个(因为它的参数只能有一个)。

注解111主要是说明了下面的情况:

(put 'real-part '(polar) real-part)

这里用的是列表polar,而不是polar符号,就是说可以出现下面的情况:

(put 'real-part '(polar rectangle) real-part-enhancement)

在我们的目前复数系统里应该不会出现这种情况,但是在后面的2.5小节里面,需要把rectangle与polar类型的加起来,就需要这么定义了:

(put 'real-part '(polar rectangle) add-enhancement)