Haskell提供了抽象代数类型(Algebra Data Type)来完成对数据的封装;其中最直观的是 data 关键字声明,可以用C/C++中的struct/class 来类比。此外,我们还可以用 type 和 newtype 来定义一些数据抽象。type所定义的就是一个已有类型的别名,其主要作用就是为了提高代码的可读性,更清晰的传达代码的意图;而newtype则有一些细微的差异和特殊作用。
newtype 的定义要求
通过newtype定义新数据类型必须满足以下要求:
1. 只能有一个构造函数,不过record语法是可以用的
2. 只能封装一个字段
看如下的例子:
1 2 3 4 5 6 7 8 |
|
最后的一个例子中,封装的字段仅仅是一个tuple,所以仍然满足只有一个字段的要求。对于有多个构造函数的data类型,不能用对应的newtype来封装一个新类型。
既然newtype
有这么多的不便,那么为什么会有人将其引入进来?对于newtype类型而言,一个最大的特点是,其构造函数在编译期间就被擦掉了,即运行期间,其构造函数是不可见的,其封装的类型和内部的field类型完全没有区别(对于类型系统而言);这样就会有巨大的性能优势:newtype类型的数据既照顾了数据抽象和代码可读性的要求,又具有尽可能少的额外处理负担;当然这些好处也带来一些很微妙的问题。
考虑如下的例子:
1 2 |
|
两种类型在运行期是没有办法相互区分的,但是在编译期间,他们是不同的type,编译器可以保证二者没有被混用;当然这个都是通过Haskell的Type checking来完成的。
Laziness
对函数进行pattern match的时候,由于构造函数实际上已经不可见,因而对newtype的构造函数进行的匹配实际上会被忽略,但是对于data类型而言,构造函数的参数数据则必须被严格赋值,如下边的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|