强制转换
在一个关于不同类型的通用算法系统中除了对同一种类型的数据进行计算外,还可能存在跨类型运算的情况,比如复数与整数的相加等。最简单的解决方法是按如下方式实现一个特殊的跨类型运算。
(define (add-complex-to-schemenum z x)
(make-from-real-imag (+ (real-part z) x) (imag-part z)))
(put 'add '(complex scheme-number)
(lambda (z x) (tag (add-complex-to-shcemenum z x))))
虽然也可以在相应的类型安装包中加入特定的跨类型算法,但这样的方式无疑是在破坏整个系统的插拔性,也破坏了系统的模块化。因为这样的某对类型专有的特殊方法既可以添加在复数包中,也可以添加在整数包中,甚至可以添加在有理数包中。所以我们应该采用能够兼顾系统插拔性和模块化的方式处理跨类型运算,这种方式通常称为 强制转换(coercion)。
强制转换是通过将两种需要转换的类型和对应的转换程式注册在强制转换表中,然后根据对应的跨类型情况调用相应的类型转换程式,这部分功能只需要改造通用程式即可获得。而且原先的所有计算程式都不需要改变,因为转换后的跨类型运算会转变为两个同类型数据对象的运算。
类型层次结构
类型转换的情况除了将 A 类型直接转换为 B 类型之外,也可能通过第三种类型进行转换,这种情况无法直接使用强制转换处理。要解决这种情况需要构建类型层次结构,如果这个结构中的每个类型都只有一种超类型和子类型则称为塔型结构。具体结构如下图。
在塔型结构中,如果需要转换类型可以逐层转换直至转换为目标类型即可。不仅如此,塔型结构中的子类型也可以自动继承超类型中的方法,因为当某个类型无法应用于对应方法时可以通过塔型结构进行转换,直到转换为符合应用方法的类型。除从下至上的转换外,也可以通过从上至下的类型转换完成简化功能,比如 6 + 0i
结果应该是整数 6
。
除了上述优点外,它也存在着不足。因为通常情况下,塔型结构并不常见,而多个子类型或多个超类型的情况才是常态。这导致无论是升级类型还是降级类型时会出现多条路径,为了确保最后能够转换为目标类型则需要查验整个类型结构网络。所以在设计大型系统时,既需要处理大量类型关系,又要保持模块化是十分困难的事情,这也是目前需要重点研究的领域。